在Node.js開發中,當遇到 buffer,stream,和二進制數據處理時,你是否像我同樣,老是感到困惑?這種感受是否會讓你認爲不瞭解它們,覺得它們不適合你,認爲而這些是Node.js做者們的事情?javascript
確實,這些東西可能很是使人生畏,尤爲是當你在缺少計算機底層基礎知識,進行相關的開發。html
可悲的是,許多教程和書籍直接告訴你如何使用 Node.js 包開發 Web 應用程序,而沒有讓你瞭解 Node.js 的核心功能以及它們存在的緣由,有些人會地告訴你,你不須要了解它們,由於你可能永遠不會直接用到這些。java
沒錯,若是你選擇作一名普通開發人員,可能永遠不會用到他們。node
若是你對這些內容存在疑問,你想理解 Node.js 的許多核心功能,好比 buffer...這就是我寫本篇文章的緣由,這是爲了幫助咱們揭開其中一些功能的神祕面紗,並使咱們對 Node.js 的學習更上一層樓。git
官方的 Node.js 文檔部分說明:github
JavaScript 語言沒有讀取或操做二進制數據流的機制。
Buffer
類被引入做爲 Node.js API 的一部分,使其能夠在 TCP 流或文件系統操做等場景中處理二進制數據流。web
嗯,除非你對上述句子中的描述有相關的知識和經驗,不然它們可能只是一堆術語。api
咱們簡化一下這些解釋,以便咱們能夠更好的理解他們,官方的描述能夠總結爲一句話:buffer 可以與二進制數據流進行交互操做。瀏覽器
可是 buffer,stream,二進制數據,仍然有不少不理解的地方。 好吧,咱們嘗試解決這些重要的問題。網絡
你可能已經知道計算機是以二進制形式存儲和表示數據,二進制只是一個1或0的集合。例如,如下是五個不一樣的二進制文件,5個不一樣的1和0集:
10,01,001,1110,00101011
二進制中的每一個數字,0或1叫作位(bit),也就是Binary digIT 的縮寫。
爲了可以存儲和表示這些數據,計算機須要將數據轉換爲二進制形式。好比,要存儲數字12,計算機須要將12轉化爲二進制 1100
計算機怎麼知道要如何去轉換?這就徹底是一個數學問題了。計算機是知道怎麼去處理的,有興趣的能夠本身查閱。
可是咱們平常工做的數據類型不只僅是數字,咱們還有字符串,圖像,視頻...計算機知道如何用二進制表示全部類型的數據的,讓咱們以字符串爲例。計算機如何用二進制表示字符串「 L」?爲了將字符存儲爲二進制形式,計算機首先將該字符轉換爲數字,而後將該數字轉換爲二進制表示,所以,對於字符串「 L」, 計算機首先將L轉換爲表明L的數字,讓咱們看如何操做:
打開瀏覽器控制檯,粘貼如下代碼段:"L".charCodeAt(0),按 Enter,你看到了什麼?數字76?這就是字母L的數字編碼,可是計算機怎麼知道具體哪一個數字表明那個字母呢?如何知道數字76表示L?
字符集是已經定義的一套規則,明確指出每一個數字表明的字符,這些規則有不一樣的定義,流行的規則包括 Unicode 和 ASCII,JavaScript 在 Unicode 字符集方面的表現很是好,實際上,在瀏覽器中,它是 Unicode(能夠嘗試其餘字符集),指出76表示大寫「L」。
咱們已經瞭解了計算機如何用數字表示字符,如今,計算機將依次將數字76表示爲其二進制形式,你可能會認爲,只需將76轉換爲以2爲底的數字系統,沒那麼快!
就像字符集規則定義那些數字表明那些字符同樣,也有一些規則定義瞭如何使用二進制形式中表示該數字,具體來講,就是使用多少位來表示數字,這就是字符編碼。
咱們常見字符編碼之一是 UTF-8,UTF-8 規定字符以字節表示,一個字節是8位(bit),即8個1和0表示一個字節,因此,用8個1和0組成的二進制序列,來表示和存儲任意的一個字符。
爲了更好的理解,舉個例子: 好比以前提到的12的二進制表示是1100。 因此,使用 UTF-8 的格式來表示,應該使用一個字節,也就是8位來完整表示,也即00001100, 沒有錯吧?
所以,76在計算機中的存儲形式應該是01001100。
這就是計算機將字符存儲成二進制的方式。固然,計算機也有一些特殊規則,將圖片、視頻等存儲爲二進制的,總之,計算機會將不管圖片、視頻或其餘數據都轉換爲二進制並存儲,這就是咱們說的二進制數據。
若是你對字符編碼很是感興趣,那你能夠參考一下這篇文章
在Node.js中,流(stream)就是一系列從A點到B點移動的數據,完整點的說,就是當你有一個很大的數據須要傳輸、搬運時,你不須要等待全部數據都傳輸完成纔開始下一步工做。
實際上,大型數據會被分割成小塊(chunks)進行傳輸。因此,buffer 的原始定義中所說的(「streams of binary data… in the context of… file system」)意思就是說二進制數據在文件系統中的傳輸。好比,將 file1.txt 的文字存儲到 file2.txt 中。
可是,buffer 到底在流(stream)中,是如何操做二進制數據的?buffer 究竟是什麼呢?
咱們已經知道數據流(stream of data)是從一個地方向另外一個地方傳輸數據的過程,可是這個具體是怎麼樣的一個過程?
一般狀況下,咱們傳輸數據每每是爲了讀取它,處理它,或者基於這些數據作一些其餘操做,可是,在每次傳輸過程當中,有一個數據量的問題。所以當獲取到數據的時間比處理數據理的時間快時,咱們處理數據就須要等待了。
這個」等待區域」就是 buffer! 它是電腦上的一個很小的物理地址,通常在內存中,數據在這裏暫時存儲,等待,最後在流(stream)中,發送出去並處理,好比說和顯卡相關的 webgl 處理就是一個例子。
咱們能夠把整個流(stream)和 buffer 的配合過程看做公交站。在一些公交站,公車在沒有裝滿乘客前是不會發車的,或者在特定的時刻纔會發車。固然,乘客也可能在不一樣的時間,人流量大小也會有所不一樣,有人多的時候,有人少的時候,乘客或公交站都沒法控制人流量。
不論什麼時候,早到的乘客都必須等待,直到公車接到指令能夠發車。當乘客到站,發現公車已經裝滿,或者已經開走,他就必須等待下一班車次。
總之,這裏總會有一個等待的地方,這個等待的區域就是 Node.js 中的 Buffer,Node.js 不能控制數據何時傳輸過來,傳輸速度,就好像公交車站沒法控制人流量同樣。他只能決定何時發送數據。若是時間還不到,那麼 Node.js 就會把數據放入 buffer(等待區域)中,一個在內存中的地址,直到把他們發送出去進行處理。
一個關於 buffer 很典型的例子,就是你在線看視頻的時候。若是你的網絡足夠快,數據流(stream)就能夠足夠快,可讓 buffer 迅速填滿而後發送和處理,而後處理另外一個,再發送,再另外一個,再發送,而後整個 stream 完成。
可是當你網絡鏈接很慢,當處理完當前的數據後,你的播放器就會暫停,或出現」緩衝」(buffer)字樣,意思是正在收集更多的數據,或者等待更多的數據到來,才能下一步處理。當buffer裝滿並處理好,播放器就會顯示數據,也就是播放視頻了。在播放當前內容的時候,更多的數據也會源源不斷的傳輸、到達和在 buffer 等待。
從原始的定義,咱們知道,buffer 能夠在 stream 中與二進制數據進行交互和操做。那麼到底能夠進行什麼樣的操做呢?在 Node.js 中又應該如何進行剛纔所描述的一些東西呢?咱們來瞧一瞧。
你能夠建立本身的緩衝區!在 stream 中,Node.js 會自動幫你建立 buffer 以外,你能夠建立本身的 buffer 並操做它,是否是頗有趣? 咱們來建立一個!
根據不一樣的需求,可使用不一樣的方法來建立緩衝區。
// 建立一個大小爲 10 的空 buffer // 這個 buffer 只能承載10個字節的內容 const buf1 = Buffer.alloc(10); // 根據內容直接建立 buffer const buf2 = Buffer.from("hello buffer"); 建立緩衝區後,就能夠操做了 // 檢查下buffer的結構 buf1.toJSON() // { type: 'Buffer', data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] } // 一個空的 buffer buf2.toJSON() // { type: 'Buffer', data: [104, 101, 108, 108, 111, 32, 98, 117, 102, 102, 101, 114] } // the toJSON() 方法能夠將數據進行 Unicode 編碼並展現 // 檢查 buffer 的大小 buf1.length // 10 buf2.length // 12 根據數據自動填充並建立 // 寫入數據到 buffer buf1.write("Buffer really rocks!") // 解碼buffer buf1.toString() // 'Buffer rea' // 對不起,由於buf1只能承載10個字節的內容,全部多處的東西會被截斷
咱們可使用 buffer 進行更多操做,前往官方文檔,進一步瞭解這些方法。
最後,我將面臨這個小挑戰:仔細閱讀 Node.js 的核心庫之一 zlib.js 的源代碼,以瞭解它如何利用 buffer 的功能來操做二進制數據流,處理後,最後變成gziped文件。 當你在閱讀的時候,記錄下你的學習經歷並在評論中分享下來吧。
但願本文能幫助你更好地瞭解 Node.js Buffer。
若是你以爲這篇文章不錯,而其餘人也有機會看到這一點,點個贊吧,以幫助其餘人更好地理解 Buffer。