這篇文章主要講解了“怎么理解Node.js中的Buffer模塊”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“怎么理解Node.js中的Buffer模塊”吧!
10年積累的網(wǎng)站建設(shè)、成都網(wǎng)站制作經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶對(duì)網(wǎng)站的新想法和需求。提供各種問(wèn)題對(duì)應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先建設(shè)網(wǎng)站后付款的網(wǎng)站建設(shè)流程,更有楊浦免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
JavaScript
對(duì)于字符串的操作十分友好
Buffer
是一個(gè)像Array
的對(duì)象,主要用于操作字節(jié)。
Buffer
是一個(gè)典型的JavaScript和C++結(jié)合的模塊,將性能相關(guān)部分用C++實(shí)現(xiàn),將非性能相關(guān)部分用JavaScript實(shí)現(xiàn)。
Buffer所占用的內(nèi)存不是通過(guò)V8分配,屬于堆外內(nèi)存。 由于V8垃圾回收性能影響,將常用的操作對(duì)象用更高效和專有的內(nèi)存分配回收政策來(lái)管理是個(gè)不錯(cuò)的思路。
Buffer在Node進(jìn)程啟動(dòng)時(shí)就已經(jīng)價(jià)值,并且放在全局對(duì)象(global)上。所以使用buffer無(wú)需require引入
Buffer對(duì)象的元素未16進(jìn)制的兩位數(shù),即0-255的數(shù)值
let buf01 = Buffer.alloc(8); console.log(buf01); // <Buffer 00 00 00 00 00 00 00 00>
可以使用fill
填充buf的值(默認(rèn)為utf-8
編碼),如果填充的值超過(guò)buffer,將不會(huì)被寫入。
如果buffer長(zhǎng)度大于內(nèi)容,則會(huì)反復(fù)填充
如果想要清空之前填充的內(nèi)容,可以直接fill()
buf01.fill('12345678910') console.log(buf01); // <Buffer 31 32 33 34 35 36 37 38> console.log(buf01.toString()); // 12345678
如果填入的內(nèi)容是中文,在utf-8
的影響下,中文字會(huì)占用3個(gè)元素,字母和半角標(biāo)點(diǎn)符號(hào)占用1個(gè)元素。
let buf02 = Buffer.alloc(18, '開(kāi)始我們的新路程', 'utf-8'); console.log(buf02.toString()); // 開(kāi)始我們的新
Buffer
受Array類型
影響很大,可以訪問(wèn)length屬性得到長(zhǎng)度,也可以通過(guò)下標(biāo)訪問(wèn)元素,也可以通過(guò)indexOf查看元素位置。
console.log(buf02); // <Buffer e5 bc 80 e5 a7 8b e6 88 91 e4 bb ac e7 9a 84 e6 96 b0> console.log(buf02.length) // 18字節(jié) console.log(buf02[6]) // 230: e6 轉(zhuǎn)換后就是 230 console.log(buf02.indexOf('我')) // 6:在第7個(gè)字節(jié)位置 console.log(buf02.slice(6, 9).toString()) // 我: 取得<Buffer e6 88 91>,轉(zhuǎn)換后就是'我'
如果給字節(jié)賦值不是0255之間的整數(shù),或者賦值時(shí)小數(shù)時(shí),賦值小于0,將該值逐次加256.直到得到0255之間的整數(shù)。如果大于255,就逐次減去255。 如果是小數(shù),舍去小數(shù)部分(不做四舍五入)
Buffer
對(duì)象的內(nèi)存分配不是在V8的堆內(nèi)存中,而是在Node的C++層面實(shí)現(xiàn)內(nèi)存的申請(qǐng)。 因?yàn)樘幚泶罅康淖止?jié)數(shù)據(jù)不能采用需要一點(diǎn)內(nèi)存就向操作系統(tǒng)申請(qǐng)一點(diǎn)內(nèi)存的方式。為此Node在內(nèi)存上使用的是在C++層面申請(qǐng)內(nèi)存,在JavaScript
中分配內(nèi)存的方式
Node
采用了slab分配機(jī)制
,slab
是以中動(dòng)態(tài)內(nèi)存管理機(jī)制,目前在一些*nix
操作系統(tǒng)用中有廣泛的應(yīng)用,比如Linux
slab
就是一塊申請(qǐng)好的固定大小的內(nèi)存區(qū)域,slab具有以下三種狀態(tài):
full:完全分配狀態(tài)
partial:部分分配狀態(tài)
empty:沒(méi)有被分配狀態(tài)
Node以8KB為界限來(lái)區(qū)分Buffer是大對(duì)象還是小對(duì)象
console.log(Buffer.poolSize); // 8192
這個(gè)8KB的值就額是每個(gè)slab的大小值,在JavaScript層面,以它作為單位單元進(jìn)行內(nèi)存的分配
如果指定Buffer
大小小于8KB,Node會(huì)按照小對(duì)象方式進(jìn)行分配
構(gòu)造一個(gè)新的slab單元,目前slab處于empty空狀態(tài)
構(gòu)造小buffer
對(duì)象1024KB,當(dāng)前的slab
會(huì)被占用1024KB,并且記錄下是從這個(gè)slab
的哪個(gè)位置開(kāi)始使用的
這時(shí)再創(chuàng)建一個(gè)buffer
對(duì)象,大小為3072KB。 構(gòu)造過(guò)程會(huì)判斷當(dāng)前slab
剩余空間是否足夠,如果足夠,使用剩余空間,并更新slab
的分配狀態(tài)。 3072KB空間被使用后,目前此slab剩余空間4096KB。
如果此時(shí)創(chuàng)建一個(gè)6144KB大小的buffer
,當(dāng)前slab空間不足,會(huì)構(gòu)造新的slab
(這會(huì)造成原slab剩余空間浪費(fèi))
比如下面的例子中:
Buffer.alloc(1) Buffer.alloc(8192)
第一個(gè)slab
中只會(huì)存在1字節(jié)的buffer對(duì)象,而后一個(gè)buffer對(duì)象會(huì)構(gòu)建一個(gè)新的slab存放
由于一個(gè)slab可能分配給多個(gè)Buffer對(duì)象使用,只有這些小buffer對(duì)象在作用域釋放并都可以回收時(shí),slab的空間才會(huì)被回收。 盡管只創(chuàng)建1字節(jié)的buffer對(duì)象,但是如果不釋放,實(shí)際是8KB的內(nèi)存都沒(méi)有釋放
小結(jié):
真正的內(nèi)存是在Node的C++層面提供,JavaScript層面只是使用。當(dāng)進(jìn)行小而頻繁的Buffer操作時(shí),采用slab的機(jī)制進(jìn)行預(yù)先申請(qǐng)和時(shí)候分配,使得JavaScript到操作系統(tǒng)之間不必有過(guò)多的內(nèi)存申請(qǐng)方面的系統(tǒng)調(diào)用。 對(duì)于大塊的buffer,直接使用C++層面提供的內(nèi)存即可,無(wú)需細(xì)膩的分配操作。
buffer在使用場(chǎng)景中,通常是以一段段的方式進(jìn)行傳輸。
const fs = require('fs'); let rs = fs.createReadStream('./靜夜思.txt', { flags:'r'}); let str = '' rs.on('data', (chunk)=>{ str += chunk; }) rs.on('end', ()=>{ console.log(str); })
以上是讀取流的范例,data時(shí)間中獲取到的chunk對(duì)象就是buffer對(duì)象。
但是當(dāng)輸入流中有寬字節(jié)編碼(一個(gè)字占多個(gè)字節(jié)
)時(shí),問(wèn)題就會(huì)暴露。在str += chunk
中隱藏了toString()
操作。等價(jià)于str = str.toString() + chunk.toString()
。
下面將可讀流的每次讀取buffer長(zhǎng)度限制為11.
fs.createReadStream('./靜夜思.txt', { flags:'r', highWaterMark: 11});
輸出得到:
上面出現(xiàn)了亂碼,上面限制了buffer長(zhǎng)度為11,對(duì)于任意長(zhǎng)度的buffer而言,寬字節(jié)字符串都有可能存在被截?cái)嗟那闆r,只不過(guò)buffer越長(zhǎng)出現(xiàn)概率越低。
但是如果設(shè)置了encoding
為utf-8
,就不會(huì)出現(xiàn)此問(wèn)題了。
fs.createReadStream('./靜夜思.txt', { flags:'r', highWaterMark: 11, encoding:'utf-8'});
原因:雖然無(wú)論怎么設(shè)置編碼,流的觸發(fā)次數(shù)都是一樣,但是在調(diào)用setEncoding
時(shí),可讀流對(duì)象在內(nèi)部設(shè)置了一個(gè)decoder對(duì)象
。每次data事件都會(huì)通過(guò)decoder對(duì)象
進(jìn)行buffer到字符串的解碼,然后傳遞給調(diào)用者。
string_decoder
模塊提供了用于將 Buffer 對(duì)象解碼為字符串(以保留編碼的多字節(jié) UTF-8 和 UTF-16 字符的方式)的 API
const { StringDecoder } = require('string_decoder'); let s1 = Buffer.from([0xe7, 0xaa, 0x97, 0xe5, 0x89, 0x8d, 0xe6, 0x98, 0x8e, 0xe6, 0x9c]) let s2 = Buffer.from([0x88, 0xe5, 0x85, 0x89, 0xef, 0xbc, 0x8c, 0x0d, 0x0a, 0xe7, 0x96]) console.log(s1.toString()); console.log(s2.toString()); console.log('------------------'); const decoder = new StringDecoder('utf8'); console.log(decoder.write(s1)); console.log(decoder.write(s2));
StringDecoder
在得到編碼之后,知道了寬字節(jié)字符串在utf-8
編碼下是以3個(gè)字節(jié)的方式存儲(chǔ)的,所以第一次decoder.write
只會(huì)輸出前9個(gè)字節(jié)轉(zhuǎn)碼的字符,后兩個(gè)字節(jié)會(huì)被保留在StringDecoder
內(nèi)部。
buffer在文件I/O和網(wǎng)絡(luò)I/O中運(yùn)用廣泛,尤其在網(wǎng)絡(luò)傳輸中,性能舉足輕重。在應(yīng)用中,通常會(huì)操作字符串,但是一旦在網(wǎng)絡(luò)中傳輸,都需要轉(zhuǎn)換成buffer,以進(jìn)行二進(jìn)制數(shù)據(jù)傳輸。 在web應(yīng)用中,字符串轉(zhuǎn)換到buffer是時(shí)時(shí)刻刻發(fā)生的,提高字符串到buffer的轉(zhuǎn)換效率,可以很大程度地提高網(wǎng)絡(luò)吞吐率。
如果通過(guò)純字符串的方式向客戶端發(fā)送,性能會(huì)比發(fā)送buffer對(duì)象更差,因?yàn)閎uffer對(duì)象無(wú)須在每次響應(yīng)時(shí)進(jìn)行轉(zhuǎn)換。通過(guò)預(yù)先轉(zhuǎn)換靜態(tài)內(nèi)容為buffer對(duì)象,可以有效地減少CPU重復(fù)使用,節(jié)省服務(wù)器資源。
可以選擇將頁(yè)面中動(dòng)態(tài)和靜態(tài)內(nèi)容分離,靜態(tài)內(nèi)容部分預(yù)先轉(zhuǎn)換為buffer的方式,使得性能得到提升。
在文件的讀取時(shí),highWaterMark
設(shè)置對(duì)性能影響至關(guān)重要。在理想狀態(tài)下,每次讀取的長(zhǎng)度就是用戶指定的highWaterMark
。
highWaterMark
大小對(duì)性能有兩個(gè)影響的點(diǎn):
對(duì)buffer內(nèi)存的分配和使用有一定影響
設(shè)置過(guò)小,可能導(dǎo)致系統(tǒng)調(diào)用次數(shù)過(guò)多
感謝各位的閱讀,以上就是“怎么理解Node.js中的Buffer模塊”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)怎么理解Node.js中的Buffer模塊這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
新聞名稱:怎么理解Node.js中的Buffer模塊
標(biāo)題鏈接:http://jinyejixie.com/article26/iehjcg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供Google、網(wǎng)站設(shè)計(jì)、面包屑導(dǎo)航、商城網(wǎng)站、虛擬主機(jī)、動(dòng)態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)