前言:碰見前端,應該是今年最幸運的事情了。然而,幸運並未就此打住。javascript
5月本身的第一份實習與惟品會邂逅html
7月本身在掘金的兩篇文章點贊數過千前端
10月本身拿到了騰訊的offerjava
如今,我在準備本身的畢設,準備下一個階段的到來。掘金社區的確是一個讓人成長的地方,我也願意從此有時間繼續分享本身的成長經歷。這篇文章是昨天看到的,通俗易懂,實在佩服,忍不住翻譯過來和你們分享,繼續成長node
你是否是和我同樣,對Node.js中的Buffer, Stream, 和 二進制數據一直都是很模糊的印象? 或者有的時候以爲,哎,我會用就好了,這些原理、底層的東西,應該交給Node.js的工程師們去理解。程序員
的確,這些名詞可能會比較初學者感到恐懼和陌生,特別是那些剛從前端轉全棧,作Node.js,卻沒有計算機基礎的同窗來講。github
可是很遺憾,不少教程或者書籍都會直接跳過這些原理和解釋的部分,直接教你怎麼使用Node.js的一些庫、工具或者API,可是對於核心的部分、爲何這樣處理和使用,卻隻字未提。甚至有些直接告訴你:「你根本不須要理解這些,由於你在工做中可能永遠不會直接使用它」api
是的,若是你想一生作一個平庸的程序員,的確能夠在工做中不直接使用。瀏覽器
然而,若是那些迷惑和模糊的概念,能引發你的好奇,並不斷保持這種好奇心去學習和探索,那麼你對Node.js的理解就會更上一層樓,而後你就會更願意去學習和了解Node.js一些核心的、原理性的東西,好比Buffer, Stream。 這也就是我寫這篇文章的緣由--去幫助你更好的、更深刻的去理解Node.js。
當說到Buffer,官方是這麼說的:
...JavaScript 語言沒有讀取或操做二進制數據流的機制。
Buffer
類被引入做爲 Node.js API 的一部分,使其能夠在 TCP 流或文件系統操做等場景中處理二進制數據流。
嗯..尷尬,除非你已經有一些計算機基礎,不然上面這句話說了只能讓你腦殼更大。咱們嘗試簡化一下,把主要含義提煉一下,能夠這麼說:
Buffer
類被引入到Node.js的API中,讓其與二進制數據流的操做和交互成爲可能
這樣是否是簡單的多了? 可是...Buffer,streams和二進制數據又是什麼東西呢?咱們從後向前,一個一個解釋下。
你應該已經知道,計算機存儲和表示數據使用二進制的。好比,下面這些是5個二進制數,5個不一樣的1和0序列:
10
, 01
, 001
, 1110
, 00101011
二進制中的每一個數字,0或1叫作位(bit),也就是Binary digIT的縮寫。
爲了可以存儲和表示這些數據,計算機須要將數據轉換爲二進制形式。好比,要存儲數字12,計算機須要將12轉化爲二進制1100
計算機怎麼知道要如何去轉換?這就徹底是一個數學問題了。計算機是知道怎麼去處理的,有興趣的能夠本身查閱。
可是,咱們平常工做的數據類型不只僅是數字。咱們還有字符、圖片甚至視頻。計算機是知道如何將這些表示爲二進制的。就拿字符來講,好比計算機如何用二進制來表示」L「這個字母。爲了將數據存儲爲二進制形式,不管任何類型的數據都會先被轉換爲數字,而後將數字轉爲二進制形式。因此爲了表示」L「,計算機首先將L轉換爲數字表示,咱們看下怎麼作到這一點。
打開你的瀏覽器控制檯,而後粘貼下面的代碼:"L".charCodeAt(0)
。你看到了什麼?數字76?這就是字母L的數字編碼。可是計算機怎麼知道具體哪一個數字表明那個字母呢?
字符集就是定義數字所表明的字符的一個規則表,一樣定義了怎樣用二進制存儲和表示。那麼,用多少位來表示一個數字,這個就叫字符編碼(Character Encoding)
有一種字符編碼叫作UTF-8。它規定了,字符應該以字節爲單位來表示。一個字節是8位(bit)。因此8個1和0組成的序列,應該用二進制來存儲和表示任意一個字符。
爲了更好的理解,舉個例子: 好比以前提到的12的二進制表示是1100
。 因此,使用UTF-8的格式來表示,應該使用一個字節,也就是8位來完整表示,也即00001100
, 沒有錯吧?
所以,76在計算機中的存儲形式應該是01001100
。
這就是計算機將字符存儲成二進制的方式。固然,計算機也有一些特殊規則,將圖片、視頻等存儲爲二進制的,總之,計算機會將不管圖片、視頻或其餘數據都轉換爲二進制並存儲,這就是咱們說的二進制數據。
若是你對字符編碼很是感興趣,那你能夠參考一下這篇文章
如今咱們瞭解了什麼是二進制數據,可是咱們介紹buffer的時候,說的**二進制數據流(streams of binary data)**又是什麼呢?
在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! 它是你電腦上的一個很小的物理地址,通常在RAM中,在這裏數據暫時的存儲、等待,最後在流(stream)中,發送過去並處理。
咱們能夠把整個流(stream)和buffer的配合過程看做公交站。在一些公交站,公車在沒有裝滿乘客前是不會發車的,或者在特定的時刻纔會發車。固然,乘客也可能在不一樣的時間,人流量大小也會有所不一樣,有人多的時候,有人少的時候,乘客或公交站都沒法控制人流量。
不論什麼時候,早到的乘客都必須等待,直到公車接到指令能夠發車。當乘客到站,發現公車已經裝滿,或者已經開走,他就必須等待下一班車次。
總之,這裏總會有一個等待的地方,這個等待的區域就是Node.js中的Buffer Node.js不能控制數據何時傳輸過來,傳輸速度,就好像公交車站沒法控制人流量同樣。他只能決定何時發送數據。若是時間還不到,那麼Node.js就會把數據放入buffer--"等待區域"中,一個在RAM中的地址,直到把他們發送出去進行處理。
一個關於buffer很典型的例子,就是你在線看視頻的時候。若是你的網絡足夠快,數據流(stream)就能夠足夠快,可讓buffer迅速填滿而後發送和處理,而後處理另外一個,再發送,再另外一個,再發送,而後整個stream完成。
可是當你網絡鏈接很慢,當處理完當前的數據後,你的播放器就會暫停,或出現"緩衝"(buffer)字樣,意思是正在收集更多的數據,或者等待更多的數據到來,才能下一步處理。當buffer裝滿並處理好,播放器就會顯示數據,也就是播放視頻了。在播放當前內容的時候,更多的數據也會源源不斷的傳輸、到達和在buffer等待。
若是播放器已經處理完或播放完前一個數據,buffer仍然沒有填滿,"buffering"(緩衝)字符就會再次出現,等待和收集更多的數據。
這就是Buffer!
從原始的定義,咱們知道,buffer能夠在stream中與二進制數據進行交互和操做。那麼到底能夠進行什麼樣的操做呢?在Node.js中又應該如何進行剛纔所描述的一些東西呢?咱們來瞧一瞧。
你甚至能夠作你本身的buffer! 在stream中,Node.js會自動幫你建立buffer以外,你能夠建立本身的buffer並操做它,是否是頗有趣? 咱們來搞一個!
根據你的需求,這裏有不一樣的建立方式,咱們一塊兒看一下吧:
// 建立一個大小爲10的空buffer
// 這個buffer只能承載10個字節的內容
const buf1 = Buffer.alloc(10);
// 根據內容直接建立buffer
const buf2 = Buffer.from("hello buffer");
複製代碼
建立了以後,你就能夠操做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個字節的內容,全部多處的東西會被截斷
//比較兩個buffers
複製代碼
固然,在Node.js中,還有更多更豐富的方法來操做buffer,你能夠參考這裏,而後去嘗試更多的方法。
最後,我想給你一個小小的挑戰:去閱讀zlib.js的源碼,一個Node.js的核心庫,去看一下它是如何利用buffer這個神器去操做二進制數據流的。處理後,最後變成gziped文件。 當你在閱讀的時候,記錄下你的學習經歷並在評論中分享下來吧。
我但願這個介紹能夠幫你更好的理解Node.js中的Buffer。
若是你以爲我這篇文章還不錯,爲了能讓更多人看到,請點個贊吧,可讓這篇文章更好的傳播,讓更多人看到。
若是你有任何問題,或者有不一樣的理解,請盡情的評論提出或者經過twitter找我哦。