摘要:在創(chuàng)建時(shí)大小已經(jīng)被確定且是無法調(diào)整的,在內(nèi)存分配這塊是由層面提供而不是具體后面會(huì)講解。在這里不知道你是否認(rèn)為這是很簡單的但是上面提到的一些關(guān)鍵詞二進(jìn)制流緩沖區(qū),這些又都是什么呢下面嘗試做一些簡單的介紹。
多數(shù)人都擁有自己不了解的能力和機(jī)會(huì),都有可能做到未曾夢想的事情。 ——戴爾·卡耐基
從前端轉(zhuǎn)入 Node.js 的童鞋對這一部分內(nèi)容會(huì)比較陌生,因?yàn)樵谇岸酥幸恍┖唵蔚淖址僮饕呀?jīng)滿足基本的業(yè)務(wù)需求,有時(shí)可能也會(huì)覺得 Buffer、Stream 這些會(huì)很神秘?;氐椒?wù)端,如果你不想只做一名普通的 Node.js 開發(fā)工程師,你應(yīng)該深入去學(xué)習(xí)一下 Buffer 揭開這一層神秘的面紗,同時(shí)也會(huì)讓你對 Node.js 的理解提升一個(gè)水平。
作者簡介:五月君,Nodejs Developer,熱愛技術(shù)、喜歡分享的 90 后青年,公眾號(hào) “Nodejs技術(shù)棧”,Github 開源項(xiàng)目 https://www.nodejs.red
Buffer初識(shí)在引入 TypedArray 之前,JavaScript 語言沒有用于讀取或操作二進(jìn)制數(shù)據(jù)流的機(jī)制。 Buffer 類是作為 Node.js API 的一部分引入的,用于在 TCP 流、文件系統(tǒng)操作、以及其他上下文中與八位字節(jié)流進(jìn)行交互。這是來自 Node.js 官網(wǎng)的一段描述,比較晦澀難懂,總結(jié)起來一句話 Node.js 可以用來處理二進(jìn)制流數(shù)據(jù)或者與之進(jìn)行交互。
Buffer 用于讀取或操作二進(jìn)制數(shù)據(jù)流,做為 Node.js API 的一部分使用時(shí)無需 require,用于操作網(wǎng)絡(luò)協(xié)議、數(shù)據(jù)庫、圖片和文件 I/O 等一些需要大量二進(jìn)制數(shù)據(jù)的場景。Buffer 在創(chuàng)建時(shí)大小已經(jīng)被確定且是無法調(diào)整的,在內(nèi)存分配這塊 Buffer 是由 C++ 層面提供而不是 V8 具體后面會(huì)講解。
在這里不知道你是否認(rèn)為這是很簡單的?但是上面提到的一些關(guān)鍵詞二進(jìn)制、流(Stream)、緩沖區(qū)(Buffer),這些又都是什么呢?下面嘗試做一些簡單的介紹。
什么是二進(jìn)制數(shù)據(jù)?談到二進(jìn)制我們大腦可能會(huì)浮想到就是 010101 這種代碼命令,如下圖所示:
正如上圖所示,二進(jìn)制數(shù)據(jù)使用 0 和 1 兩個(gè)數(shù)碼來表示的數(shù)據(jù),為了存儲(chǔ)或展示一些數(shù)據(jù),計(jì)算機(jī)需要先將這些數(shù)據(jù)轉(zhuǎn)換為二進(jìn)制來表示。例如,我想存儲(chǔ) 66 這個(gè)數(shù)字,計(jì)算機(jī)會(huì)先將數(shù)字 66 轉(zhuǎn)化為二進(jìn)制 01000010 表示,印象中第一次接觸這個(gè)是在大學(xué)期間 C 語言課程中,轉(zhuǎn)換公式如下所示:
128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
---|---|---|---|---|---|---|---|
0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 |
上面用數(shù)字舉了一個(gè)示例,我們知道數(shù)字只是數(shù)據(jù)類型之一,其它的還有字符串、圖像、文件等。例如我們對一個(gè)英文 M 操作,在 JavaScript 里通過 "M".charCodeAt() 取到對應(yīng)的 ASCII 碼之后(通過以上的步驟)會(huì)轉(zhuǎn)為二進(jìn)制表示。
什么是 Stream?流,英文 Stream 是對輸入輸出設(shè)備的抽象,這里的設(shè)備可以是文件、網(wǎng)絡(luò)、內(nèi)存等。
流是有方向性的,當(dāng)程序從某個(gè)數(shù)據(jù)源讀入數(shù)據(jù),會(huì)開啟一個(gè)輸入流,這里的數(shù)據(jù)源可以是文件或者網(wǎng)絡(luò)等,例如我們從 a.txt 文件讀入數(shù)據(jù)。相反的當(dāng)我們的程序需要寫出數(shù)據(jù)到指定數(shù)據(jù)源(文件、網(wǎng)絡(luò)等)時(shí),則開啟一個(gè)輸出流。當(dāng)有一些大文件操作時(shí),我們就需要 Stream 像管道一樣,一點(diǎn)一點(diǎn)的將數(shù)據(jù)流出。
舉個(gè)例子
我們現(xiàn)在有一大罐水需要澆一片菜地,如果我們將水罐的水一下全部倒入菜地,首先得需要有多么大的力氣(這里的力氣好比計(jì)算機(jī)中的硬件性能)才可搬得動(dòng)。如果,我們拿來了水管將水一點(diǎn)一點(diǎn)流入我們的菜地,這個(gè)時(shí)候不要這么大力氣就可完成。
通過上面的講解進(jìn)一步的理解了 Stream 是什么?那么 Stream 和 Buffer 之間又是什么關(guān)系呢?看以下介紹,關(guān)于 Stream 本身也有很多知識(shí)點(diǎn),歡迎關(guān)注公眾號(hào)「Nodejs技術(shù)?!?,之后會(huì)多帶帶進(jìn)行介紹。
什么是 Buffer?通過以上 Stream 的講解,我們已經(jīng)看到數(shù)據(jù)是從一端流向另一端,那么他們是如何流動(dòng)的呢?
通常,數(shù)據(jù)的移動(dòng)是為了處理或者讀取它,并根據(jù)它進(jìn)行決策。伴隨著時(shí)間的推移,每一個(gè)過程都會(huì)有一個(gè)最小或最大數(shù)據(jù)量。如果數(shù)據(jù)到達(dá)的速度比進(jìn)程消耗的速度快,那么少數(shù)早到達(dá)的數(shù)據(jù)會(huì)處于等待區(qū)等候被處理。反之,如果數(shù)據(jù)到達(dá)的速度比進(jìn)程消耗的數(shù)據(jù)慢,那么早先到達(dá)的數(shù)據(jù)需要等待一定量的數(shù)據(jù)到達(dá)之后才能被處理。
這里的等待區(qū)就指的緩沖區(qū)(Buffer),它是計(jì)算機(jī)中的一個(gè)小物理單位,通常位于計(jì)算機(jī)的 RAM 中。這些概念可能會(huì)很難理解,不要擔(dān)心下面通過一個(gè)例子進(jìn)一步說明。
公共汽車站乘車?yán)?/strong>
舉一個(gè)公共汽車站乘車的例子,通常公共汽車會(huì)每隔幾十分鐘一趟,在這個(gè)時(shí)間到達(dá)之前就算乘客已經(jīng)滿了,車輛也不會(huì)提前發(fā)車,早到的乘客就需要先在車站進(jìn)行等待。假設(shè)到達(dá)的乘客過多,后到的一部分則需要在公共汽車站等待下一趟車駛來。
在上面例子中的等待區(qū)公共汽車站,對應(yīng)到我們的 Node.js 中也就是緩沖區(qū)(Buffer),另外乘客到達(dá)的速度是我們不能控制的,我們能控制的也只有何時(shí)發(fā)車,對應(yīng)到我們的程序中就是我們無法控制數(shù)據(jù)流到達(dá)的時(shí)間,可以做的是能決定何時(shí)發(fā)送數(shù)據(jù)。
Buffer基本使用了解了 Buffer 的一些概念之后,我們來看下 Buffer 的一些基本使用,這里并不會(huì)列舉所有的 API 使用,僅列舉一部分常用的,更詳細(xì)的可參考 Node.js 中文網(wǎng)。
創(chuàng)建Buffer在 6.0.0 之前的 Node.js 版本中, Buffer 實(shí)例是使用 Buffer 構(gòu)造函數(shù)創(chuàng)建的,該函數(shù)根據(jù)提供的參數(shù)以不同方式分配返回的 Buffer new Buffer()。
現(xiàn)在可以通過 Buffer.from()、Buffer.alloc() 與 Buffer.allocUnsafe() 三種方式來創(chuàng)建
Buffer.from()
const b1 = Buffer.from("10"); const b2 = Buffer.from("10", "utf8"); const b3 = Buffer.from([10]); const b4 = Buffer.from(b3); console.log(b1, b2, b3, b4); //
Buffer.alloc
返回一個(gè)已初始化的 Buffer,可以保證新創(chuàng)建的 Buffer 永遠(yuǎn)不會(huì)包含舊數(shù)據(jù)。
const bAlloc1 = Buffer.alloc(10); // 創(chuàng)建一個(gè)大小為 10 個(gè)字節(jié)的緩沖區(qū) console.log(bAlloc1); //
Buffer.allocUnsafe
創(chuàng)建一個(gè)大小為 size 字節(jié)的新的未初始化的 Buffer,由于 Buffer 是未初始化的,因此分配的內(nèi)存片段可能包含敏感的舊數(shù)據(jù)。在 Buffer 內(nèi)容可讀情況下,則可能會(huì)泄露它的舊數(shù)據(jù),這個(gè)是不安全的,使用時(shí)要謹(jǐn)慎。
const bAllocUnsafe1 = Buffer.allocUnsafe(10); console.log(bAllocUnsafe1); //Buffer 字符編碼
通過使用字符編碼,可實(shí)現(xiàn) Buffer 實(shí)例與 JavaScript 字符串之間的相互轉(zhuǎn)換,目前所支持的字符編碼如下所示:
"ascii" - 僅適用于 7 位 ASCII 數(shù)據(jù)。此編碼速度很快,如果設(shè)置則會(huì)剝離高位。
"utf8" - 多字節(jié)編碼的 Unicode 字符。許多網(wǎng)頁和其他文檔格式都使用 UTF-8。
"utf16le" - 2 或 4 個(gè)字節(jié),小端序編碼的 Unicode 字符。支持代理對(U+10000 至 U+10FFFF)。
"ucs2" - "utf16le" 的別名。
"base64" - Base64 編碼。當(dāng)從字符串創(chuàng)建 Buffer 時(shí),此編碼也會(huì)正確地接受 RFC 4648 第 5 節(jié)中指定的 “URL 和文件名安全字母”。
"latin1" - 一種將 Buffer 編碼成單字節(jié)編碼字符串的方法(由 RFC 1345 中的 IANA 定義,第 63 頁,作為 Latin-1 的補(bǔ)充塊和 C0/C1 控制碼)。
"binary" - "latin1" 的別名。
"hex" - 將每個(gè)字節(jié)編碼成兩個(gè)十六進(jìn)制的字符。
const buf = Buffer.from("hello world", "ascii"); console.log(buf.toString("hex")); // 68656c6c6f20776f726c64字符串與 Buffer 類型互轉(zhuǎn)
字符串轉(zhuǎn) Buffer
這個(gè)相信不會(huì)陌生了,通過上面講解的 Buffer.form() 實(shí)現(xiàn),如果不傳遞 encoding 默認(rèn)按照 UTF-8 格式轉(zhuǎn)換存儲(chǔ)
const buf = Buffer.from("Node.js 技術(shù)棧", "UTF-8"); console.log(buf); //console.log(buf.length); // 17
Buffer 轉(zhuǎn)換為字符串
Buffer 轉(zhuǎn)換為字符串也很簡單,使用 toString([encoding], [start], [end]) 方法,默認(rèn)編碼仍為 UTF-8,如果不傳 start、end 可實(shí)現(xiàn)全部轉(zhuǎn)換,傳了 start、end 可實(shí)現(xiàn)部分轉(zhuǎn)換(這里要小心了)
const buf = Buffer.from("Node.js 技術(shù)棧", "UTF-8"); console.log(buf); //console.log(buf.length); // 17 console.log(buf.toString("UTF-8", 0, 9)); // Node.js ?
運(yùn)行查看,可以看到以上輸出結(jié)果為 Node.js ? 出現(xiàn)了亂碼,為什么?
轉(zhuǎn)換過程中為什么出現(xiàn)亂碼?
首先以上示例中使用的默認(rèn)編碼方式 UTF-8,問題就出在這里一個(gè)中文在 UTF-8 下占用 3 個(gè)字節(jié),技 這個(gè)字在 buf 中對應(yīng)的字節(jié)為 8a 80 e6
而我們的設(shè)定的范圍為 0~9 因此只輸出了 8a,這個(gè)時(shí)候就會(huì)造成字符被截?cái)喑霈F(xiàn)亂碼。
下面我們改下示例的截取范圍:
const buf = Buffer.from("Node.js 技術(shù)棧", "UTF-8"); console.log(buf); //console.log(buf.length); // 17 console.log(buf.toString("UTF-8", 0, 11)); // Node.js 技
可以看到已經(jīng)正常輸出了
Buffer內(nèi)存機(jī)制在 Nodejs 中的 內(nèi)存管理和 V8 垃圾回收機(jī)制 一節(jié)主要講解了在 Node.js 的垃圾回收中主要使用 V8 來管理,但是并沒有提到 Buffer 類型的數(shù)據(jù)是如何回收的,下面讓我們來了解 Buffer 的內(nèi)存回收機(jī)制。
由于 Buffer 需要處理的是大量的二進(jìn)制數(shù)據(jù),假如用一點(diǎn)就向系統(tǒng)去申請,則會(huì)造成頻繁的向系統(tǒng)申請內(nèi)存調(diào)用,所以 Buffer 所占用的內(nèi)存不再由 V8 分配,而是在 Node.js 的 C++ 層面完成申請,在 JavaScript 中進(jìn)行內(nèi)存分配。因此,這部分內(nèi)存我們稱之為堆外內(nèi)存。
注意:以下使用到的 buffer.js 源碼為 Node.js v10.x 版本,地址:https://github.com/nodejs/node/blob/v10.x/lib/buffer.js
Buffer內(nèi)存分配原理Node.js 采用了 slab 機(jī)制進(jìn)行預(yù)先申請、事后分配,是一種動(dòng)態(tài)的管理機(jī)制。
使用 Buffer.alloc(size) 傳入一個(gè)指定的 size 就會(huì)申請一塊固定大小的內(nèi)存區(qū)域,slab 具有如下三種狀態(tài):
full:完全分配狀態(tài)
partial:部分分配狀態(tài)
empty:沒有被分配狀態(tài)
8KB 限制
Node.js 以 8KB 為界限來區(qū)分是小對象還是大對象,在 buffer.js 中可以看到以下代碼
Buffer.poolSize = 8 * 1024; // 102 行,Node.js 版本為 v10.x
在 Buffer 初識(shí) 一節(jié)里有提到過 Buffer 在創(chuàng)建時(shí)大小已經(jīng)被確定且是無法調(diào)整的 到這里應(yīng)該就明白了。
Buffer 對象分配
以下代碼示例,在加載時(shí)直接調(diào)用了 createPool() 相當(dāng)于直接初始化了一個(gè) 8 KB 的內(nèi)存空間,這樣在第一次進(jìn)行內(nèi)存分配時(shí)也會(huì)變得更高效。另外在初始化的同時(shí)還初始化了一個(gè)新的變量 poolOffset = 0 這個(gè)變量會(huì)記錄已經(jīng)使用了多少字節(jié)。
Buffer.poolSize = 8 * 1024; var poolSize, poolOffset, allocPool; ... // 中間代碼省略 function createPool() { poolSize = Buffer.poolSize; allocPool = createUnsafeArrayBuffer(poolSize); poolOffset = 0; } createPool(); // 129 行
此時(shí),新構(gòu)造的 slab 如下所示:
現(xiàn)在讓我們來嘗試分配一個(gè)大小為 2048 的 Buffer 對象,代碼如下所示:
Buffer.alloc(2 * 1024)
現(xiàn)在讓我們先看下當(dāng)前的 slab 內(nèi)存是怎么樣的?如下所示:
那么這個(gè)分配過程是怎樣的呢?讓我們再看 buffer.js 另外一個(gè)核心的方法 allocate(size)
// https://github.com/nodejs/node/blob/v10.x/lib/buffer.js#L318 function allocate(size) { if (size <= 0) { return new FastBuffer(); } // 當(dāng)分配的空間小于 Buffer.poolSize 向右移位,這里得出來的結(jié)果為 4KB if (size < (Buffer.poolSize >>> 1)) { if (size > (poolSize - poolOffset)) createPool(); var b = new FastBuffer(allocPool, poolOffset, size); poolOffset += size; // 已使用空間累加 alignPool(); // 8 字節(jié)內(nèi)存對齊處理 return b; } else { // C++ 層面申請 return createUnsafeBuffer(size); } }
讀完上面的代碼,已經(jīng)很清晰的可以看到何時(shí)會(huì)分配小 Buffer 對象,又何時(shí)會(huì)去分配大 Buffer 對象。
Buffer 內(nèi)存分配總結(jié)這塊內(nèi)容著實(shí)難理解,翻了幾本 Node.js 相關(guān)書籍,樸靈大佬的「深入淺出 Node.js」Buffer 一節(jié)還是講解的挺詳細(xì)的,推薦大家去閱讀下。
在初次加載時(shí)就會(huì)初始化 1 個(gè) 8KB 的內(nèi)存空間,buffer.js 源碼有體現(xiàn)
根據(jù)申請的內(nèi)存大小分為 小 Buffer 對象 和 大 Buffer 對象
小 Buffer 情況,會(huì)繼續(xù)判斷這個(gè) slab 空間是否足夠
如果空間足夠就去使用剩余空間同時(shí)更新 slab 分配狀態(tài),偏移量會(huì)增加
如果空間不足,slab 空間不足,就會(huì)去創(chuàng)建一個(gè)新的 slab 空間用來分配
大 Buffer 情況,則會(huì)直接走 createUnsafeBuffer(size) 函數(shù)
不論是小 Buffer 對象還是大 Buffer 對象,內(nèi)存分配是在 C++ 層面完成,內(nèi)存管理在 JavaScript 層面,最終還是可以被 V8 的垃圾回收標(biāo)記所回收。
Buffer應(yīng)用場景以下列舉一些 Buffer 在實(shí)際業(yè)務(wù)中的應(yīng)用場景,也歡迎大家在評論區(qū)補(bǔ)充!
I/O 操作關(guān)于 I/O 可以是文件或網(wǎng)絡(luò) I/O,以下為通過流的方式將 input.txt 的信息讀取出來之后寫入到 output.txt 文件,關(guān)于 Stream 與 Buffer 的關(guān)系不明白的在回頭看下 Buffer 初識(shí) 一節(jié)講解的 什么是 Stream?、什么是 Buffer?
const fs = require("fs"); const inputStream = fs.createReadStream("input.txt"); // 創(chuàng)建可讀流 const outputStream = fs.createWriteStream("output.txt"); // 創(chuàng)建可寫流 inputStream.pipe(outputStream); // 管道讀寫
在 Stream 中我們是不需要手動(dòng)去創(chuàng)建自己的緩沖區(qū),在 Node.js 的流中將會(huì)自動(dòng)創(chuàng)建。
zlib.jszlib.js 為 Node.js 的核心庫之一,其利用了緩沖區(qū)(Buffer)的功能來操作二進(jìn)制數(shù)據(jù)流,提供了壓縮或解壓功能。參考源代碼 zlib.js 源碼
加解密在一些加解密算法中會(huì)遇到使用 Buffer,例如 crypto.createCipheriv 的第二個(gè)參數(shù) key 為 String 或 Buffer 類型,如果是 Buffer 類型,就用到了本篇我們講解的內(nèi)容,以下做了一個(gè)簡單的加密示例,重點(diǎn)使用了 Buffer.alloc() 初始化一個(gè)實(shí)例(這個(gè)上面有介紹),之后使用了 fill 方法做了填充,這里重點(diǎn)在看下這個(gè)方法的使用。
buf.fill(value[, offset[, end]][, encoding])
value: 第一個(gè)參數(shù)為要填充的內(nèi)容
offset: 偏移量,填充的起始位置
end: 結(jié)束填充 buf 的偏移量
encoding: 編碼集
以下為 Cipher 的對稱加密 Demo
const crypto = require("crypto"); const [key, iv, algorithm, encoding, cipherEncoding] = [ "a123456789", "", "aes-128-ecb", "utf8", "base64" ]; const handleKey = key => { const bytes = Buffer.alloc(16); // 初始化一個(gè) Buffer 實(shí)例,每一項(xiàng)都用 00 填充 console.log(bytes); //Buffer VS Cachebytes.fill(key, 0, 10) // 填充 console.log(bytes); // return bytes; } let cipher = crypto.createCipheriv(algorithm, handleKey(key), iv); let crypted = cipher.update("Node.js 技術(shù)棧", encoding, cipherEncoding); crypted += cipher.final(cipherEncoding); console.log(crypted) // jE0ODwuKN6iaKFKqd3RF4xFZkOpasy8WfIDl8tRC5t0=
緩沖(Buffer)與緩存(Cache)的區(qū)別?
緩沖(Buffer)
緩沖(Buffer)是用于處理二進(jìn)制流數(shù)據(jù),將數(shù)據(jù)緩沖起來,它是臨時(shí)性的,對于流式數(shù)據(jù),會(huì)采用緩沖區(qū)將數(shù)據(jù)臨時(shí)存儲(chǔ)起來,等緩沖到一定的大小之后在存入硬盤中。視頻播放器就是一個(gè)經(jīng)典的例子,有時(shí)你會(huì)看到一個(gè)緩沖的圖標(biāo),這意味著此時(shí)這一組緩沖區(qū)并未填滿,當(dāng)數(shù)據(jù)到達(dá)填滿緩沖區(qū)并且被處理之后,此時(shí)緩沖圖標(biāo)消失,你可以看到一些圖像數(shù)據(jù)。
緩存(Cache)
緩存(Cache)我們可以看作是一個(gè)中間層,它可以是永久性的將熱點(diǎn)數(shù)據(jù)進(jìn)行緩存,使得訪問速度更快,例如我們通過 Memory、Redis 等將數(shù)據(jù)從硬盤或其它第三方接口中請求過來進(jìn)行緩存,目的就是將數(shù)據(jù)存于內(nèi)存的緩存區(qū)中,這樣對同一個(gè)資源進(jìn)行訪問,速度會(huì)更快,也是性能優(yōu)化一個(gè)重要的點(diǎn)。
來自知乎的一個(gè)討論,點(diǎn)擊 more 查看
Buffer VS String通過壓力測試來看看 String 和 Buffer 兩者的性能如何?
const http = require("http"); let s = ""; for (let i=0; i<1024*10; i++) { s+="a" } const str = s; const bufStr = Buffer.from(s); const server = http.createServer((req, res) => { console.log(req.url); if (req.url === "/buffer") { res.end(bufStr); } else if (req.url === "/string") { res.end(str); } }); server.listen(3000);
以上實(shí)例我放在虛擬機(jī)里進(jìn)行測試,你也可以在本地電腦測試,使用 AB 測試工具。
測試 string
看以下幾個(gè)重要的參數(shù)指標(biāo),之后通過 buffer 傳輸進(jìn)行對比
Complete requests: 21815
Requests per second: 363.58 [#/sec] (mean)
Transfer rate: 3662.39 [Kbytes/sec] received
$ ab -c 200 -t 60 http://192.168.6.131:3000/string
測試 buffer
可以看到通過 buffer 傳輸總共的請求數(shù)為 50000、QPS 達(dá)到了兩倍多的提高、每秒傳輸?shù)淖止?jié)為 9138.82 KB,從這些數(shù)據(jù)上可以證明提前將數(shù)據(jù)轉(zhuǎn)換為 Buffer 的方式,可以使性能得到近一倍的提升。
Complete requests: 50000
Requests per second: 907.24 [#/sec] (mean)
Transfer rate: 9138.82 [Kbytes/sec] received
$ ab -c 200 -t 60 http://192.168.6.131:3000/buffer
在 HTTP 傳輸中傳輸?shù)氖嵌M(jìn)制數(shù)據(jù),上面例子中的 /string 接口直接返回的字符串,這時(shí)候 HTTP 在傳輸之前會(huì)先將字符串轉(zhuǎn)換為 Buffer 類型,以二進(jìn)制數(shù)據(jù)傳輸,通過流(Stream)的方式一點(diǎn)點(diǎn)返回到客戶端。但是直接返回 Buffer 類型,則少了每次的轉(zhuǎn)換操作,對于性能也是有提升的。
在一些 Web 應(yīng)用中,對于靜態(tài)數(shù)據(jù)可以預(yù)先轉(zhuǎn)為 Buffer 進(jìn)行傳輸,可以有效減少 CPU 的重復(fù)使用(重復(fù)的字符串轉(zhuǎn) Buffer 操作)。
Referencehttp://nodejs.cn/api/buffer.html
深入淺出 Node.js Buffer
Do you want a better understanding of Buffer in Node.js? Check this out.
A cartoon intro to ArrayBuffers and SharedArrayBuffers
buffer.js v10.x
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/106079.html
摘要:究竟是什么是一個(gè)運(yùn)行時(shí)環(huán)境。對此請求的響應(yīng)需要時(shí)間,但兩個(gè)用戶數(shù)據(jù)請求可以獨(dú)立并同時(shí)執(zhí)行。所以這會(huì)使不太適合多線程任務(wù)。這種非阻塞消除了多線程的需要,因?yàn)榉?wù)器可以同時(shí)處理多個(gè)請求。該事件將等待毫秒,然后回調(diào)函數(shù)。系統(tǒng)事件來自庫的核心。 Node.js究竟是什么? Node.js是一個(gè)JavaScript運(yùn)行時(shí)環(huán)境。聽起來不錯(cuò),但這是什么意思?這是如何運(yùn)作的? Node運(yùn)行時(shí)環(huán)境包含執(zhí)...
摘要:究竟是什么是一個(gè)運(yùn)行時(shí)環(huán)境。對此請求的響應(yīng)需要時(shí)間,但兩個(gè)用戶數(shù)據(jù)請求可以獨(dú)立并同時(shí)執(zhí)行。所以這會(huì)使不太適合多線程任務(wù)。這種非阻塞消除了多線程的需要,因?yàn)榉?wù)器可以同時(shí)處理多個(gè)請求。該事件將等待毫秒,然后回調(diào)函數(shù)。系統(tǒng)事件來自庫的核心。 Node.js究竟是什么? Node.js是一個(gè)JavaScript運(yùn)行時(shí)環(huán)境。聽起來不錯(cuò),但這是什么意思?這是如何運(yùn)作的? Node運(yùn)行時(shí)環(huán)境包含執(zhí)...
摘要:當(dāng)某個(gè)執(zhí)行完畢時(shí),將以事件的形式通知執(zhí)行操作的線程,線程執(zhí)行這個(gè)事件的回調(diào)函數(shù)。為了處理異步,線程必須有事件循環(huán),不斷的檢查有沒有未處理的事件,依次予以處理。另外,單線程帶來的好處,操作系統(tǒng)完全不再有線程創(chuàng)建銷毀的時(shí)間開銷。 前言 如果你有一定的前端基礎(chǔ),比如 HTML、CSS、JavaScript、jQuery;那么,Node.js 能讓你以最低的成本快速過渡成為一個(gè)全棧工程師(我稱...
摘要:在回調(diào)隊(duì)列中,函數(shù)等待調(diào)用棧為空,因?yàn)槊總€(gè)語句都執(zhí)行一次。最后一個(gè)運(yùn)行,并且從調(diào)用棧中彈出。它將回調(diào)以先進(jìn)先出順序移動(dòng)到調(diào)用棧并執(zhí)行。 翻譯:瘋狂的技術(shù)宅原文: https://medium.freecodecamp.o... 本文首發(fā)微信公眾號(hào):前端先鋒歡迎關(guān)注,每天都給你推送新鮮的前端技術(shù)文章 Node.js 是一個(gè) JavaScript 運(yùn)行時(shí)環(huán)境。聽起來還不錯(cuò),不過這究竟...
閱讀 3116·2021-10-11 10:58
閱讀 2017·2021-09-24 09:47
閱讀 516·2019-08-30 14:19
閱讀 1727·2019-08-30 13:58
閱讀 1454·2019-08-29 15:26
閱讀 652·2019-08-26 13:45
閱讀 2150·2019-08-26 11:53
閱讀 1786·2019-08-26 11:30