亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Nodejs Buffer的使用及Stream流和事件機(jī)制詳解

 更新時(shí)間:2022年10月18日 15:03:08   作者:SaraiNoQ  
這篇文章主要為大家介紹了Nodejs Buffer的使用及Stream流和事件機(jī)制詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

昨天我們講述了 Buffer類 的基礎(chǔ)用法,今天我們介紹一下 Buffer類 的一些應(yīng)用以及 流(Stream) 的概念和用法。

Buffer 使用

Buffer 拼接

Buffer 在使用時(shí),通常是以一段一段的方式傳輸。以下是一段經(jīng)典的從輸入流中讀取內(nèi)容的代碼:

const fs = require("fs");
// const readFs = fs.createReadStream("./readExam.md", {
//   highWaterMark: 1
// });
const readFs = fs.createReadStream("./readExam.md");
let data = "";
readFs.on("data", (chunk) => {
    data += chunk;
});
readFs.on("end", () => {
    console.log("buffer value: ", data);
});

?? data事件中獲取的 chunk對(duì)象Buffer對(duì)象String對(duì)象,然后與 data變量 拼接成目標(biāo) Buffer對(duì)象。

上述的代碼中我們構(gòu)造了一個(gè)可讀流。值得一提的是,可讀流有一個(gè)設(shè)置編碼的方法:

readable.setEncoding(encoding);

該方法能指定 data事件 中傳遞的元素的編碼類型,避免發(fā)生一些特殊的錯(cuò)誤:

const readFs = fs.createReadStream("./readExam.md");
readFs.setEncoding('utf-8');

編碼問(wèn)題

在不設(shè)置 highWaterMark 屬性的情況下,你無(wú)需顯示地去調(diào)用 setEncoding 方法,data事件默認(rèn)就能接受字符串或者 Buffer 對(duì)象兩種參數(shù)。但你仍需注意,目前僅支持 UTF8UTF16LE 兩種編碼的字符串,所以如果讀取的目標(biāo)文件是其他編碼的,打印結(jié)果將會(huì)是亂碼!

?? 假設(shè)每讀取一個(gè)Buffer就會(huì)觸發(fā)一次data事件,那么無(wú)論如何設(shè)置編碼,觸發(fā)data事件的次數(shù)依舊相同。也就是說(shuō),如果你讀的文件中內(nèi)容是漢字,要觸發(fā)三次data事件才會(huì)進(jìn)行一次拼接。因此在這種情況下中文會(huì)出現(xiàn)亂碼。

而在調(diào)用setEncoding()時(shí),可讀流對(duì)象在內(nèi)部設(shè)置了一個(gè)decoder對(duì)象。每次data事件都通過(guò)該decoder對(duì)象進(jìn)行Buffer到字符串的解碼,然后傳遞給調(diào)用者。而decoder內(nèi)部是會(huì)對(duì)是否為寬字節(jié)進(jìn)行判斷,從而進(jìn)行轉(zhuǎn)碼。

拼接的正確姿勢(shì)

正確的拼接方式是用一個(gè)數(shù)組來(lái)存儲(chǔ)接收到的所有Buffer片段并記錄下所有片段的總長(zhǎng)度,然后調(diào)用Buffer.concat() 方法生成一個(gè)合并的Buffer對(duì)象。

const fs = require("fs");
const readFs = fs.createReadStream("./readExam.md");
let chunks = [];
let size = 0;
readFs.on("data", (chunk) => {
  const chunkBuf = new Buffer.from(chunk);
  chunks.push(chunkBuf);
  size += chunkBuf.length;
});
readFs.on("end", () => {
  const buf = Buffer.concat(chunks, size);
  const str = buf.toString(); // 對(duì)應(yīng)編碼方式,如果不支持則需要引入外部庫(kù)
})

文件讀取

?? Nodejs 提供了一個(gè)通過(guò) Buffer 讀取文件的方法 fs.readFile(),可以簡(jiǎn)化讀取文件的操作。同時(shí)該方法還有 Sync 模式,及它的同步方法,返回一個(gè)Buffer對(duì)象。

但是注意,由于V8的內(nèi)存限制,你無(wú)法通過(guò) fs.readFile()fs.writeFile() 直接對(duì)大文件進(jìn)行字符串操作,而需改用 fs.createReadStream()fs.createWriteStream() 方法通過(guò)流的方式實(shí)現(xiàn)對(duì)大文件的操作。具體請(qǐng)參考接下來(lái)的 Stream 的介紹。

而如果不需要進(jìn)行字符串層面的操作,則不需要借助V8來(lái)處理,只進(jìn)行純粹的Buffer操作,這不會(huì)受到V8堆內(nèi)存的限制,只會(huì)受到電腦物理內(nèi)存的限制。

性能

Buffer 的使用除了與字符串的轉(zhuǎn)換有性能損耗外,在文件的讀取時(shí),有一個(gè)highWaterMark設(shè)置對(duì)性能的影響至關(guān)重要。其默認(rèn)值為64KB。

fs.createReadStream()的工作方式是在內(nèi)存中準(zhǔn)備一段Buffer內(nèi)存,然后在fs.read()讀取時(shí)逐步從磁盤(pán)中將字節(jié)復(fù)制到Buffer內(nèi)存中。完成一次讀取時(shí),則從這個(gè)Buffer中通過(guò)slice()方法取出部分?jǐn)?shù)據(jù)作為一個(gè)小Buffer對(duì)象,再通過(guò)data事件傳遞給調(diào)用方。如果Buffer用完,則重新分配一個(gè);如果還有剩余,則繼續(xù)使用。而每次讀取的長(zhǎng)度就是戶指定的 highWaterMark ,在合理范圍內(nèi),該值越大,讀取速度越快。

fs.createReadStream(path, [options])

?? 最開(kāi)始我們將 highWaterMark 設(shè)置為 1 ,然后讀取中文出現(xiàn)亂碼也是這個(gè)原因

在網(wǎng)絡(luò)中的應(yīng)用

在Web應(yīng)用中,字符串轉(zhuǎn)換到Buffer是時(shí)時(shí)刻刻發(fā)生的,提高字符串到Buffer的轉(zhuǎn)換效率,可以很大程度地提高網(wǎng)絡(luò)吞吐率。因此,Nodejs內(nèi)部會(huì)通過(guò)預(yù)先轉(zhuǎn)換靜態(tài)內(nèi)容為Buffer對(duì)象緩存著,以減少CPU的重復(fù)使用,節(jié)省服務(wù)器資源。

const http = require('http');
const HOST = "127.0.0.1";
const PORT = 6869;
const server = http.createServer();
server.listen({
  port: PORT,
  host: HOST
}, () => {
  console.log(`server listen on `, server.address());
});
let resData = "";
for (let i = 0; i < 1024*10; i++) {
  resData += "a";
}
// resData = new Buffer.from(resData);
// 監(jiān)聽(tīng)客戶端發(fā)起的 request 
server.on('request', (req, res) => {
  console.log('connect success!\n');
  res.writeHead(200);
  res.end(resData);
})
server.on('clientError', (err, socket) => {
  socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});

?? 你無(wú)需顯示地調(diào)用18行代碼。

流 Stream

Nodejs 中原生內(nèi)置的 stream模塊 用于處理流式數(shù)據(jù),許多核心模塊都在其內(nèi)部實(shí)現(xiàn)了流操作。流還適用于網(wǎng)絡(luò)傳輸、JSON解析器、RFC(遠(yuǎn)程調(diào)用)等。Stream 繼承自 EventEmitter,具備基本的自定義事件功能,同時(shí)抽象出標(biāo)準(zhǔn)的事件和方法它擁有四個(gè)抽象類:

  • Readable:可讀流,讀取底層的I/O數(shù)據(jù)源。
  • Writeable:可寫(xiě)流,將數(shù)據(jù)寫(xiě)入到目標(biāo)中。
  • Duplex:雙工流,即可讀也可寫(xiě)。
  • Transform:轉(zhuǎn)換流,會(huì)修改數(shù)據(jù)的雙工流。

管道 pipe()

在可讀流中,有一個(gè)管道方法:pipe(),它的作用是關(guān)聯(lián)可讀流與可寫(xiě)流,讓數(shù)據(jù)通過(guò)管道從可讀流進(jìn)入到可寫(xiě)流中。pipe()方法能接收一個(gè)Writable對(duì)象,并返回對(duì)目標(biāo)流的引用,從而可形成鏈?zhǔn)秸{(diào)用。

你可以用這個(gè)方法改寫(xiě)之前的案例:

const fs = require('fs');
const readable = fs.createReadStream('./origin.txt');
const writable = fs.createWriteStream('./target.txt');
readable.pipe(writable);
const fs = require("fs");
const readFs = fs.createReadStream("./readExam.md");
const writeFs = fs.createWriteStream("./outExam.md");
// 1.writ+end
readFs.on("data", (chunk) => {
    // writeFs.write(chunk);
});
readFs.on("end", () => {
  // writeFs.end();
})
// 2.pipe
readFs.pipe(writeFs);

?? 之前我們提到的內(nèi)存限制,是因?yàn)閂8本身是有內(nèi)存限制的,而通過(guò)

EventEmitter

Nodejs 的事件模塊目前只包含一個(gè) EventEmitter類(即事件觸發(fā)器),所有能觸發(fā)事件的對(duì)象都是 EventEmitter類 的實(shí)例。EventEmitter 通常被用作基類,在 Nodejs 內(nèi)部,凡是提供事件機(jī)制的模塊都會(huì)繼承它。

聲明了一個(gè)EventEmitter實(shí)例,on()方法用于注冊(cè)監(jiān)聽(tīng)器,emit()方法用于觸發(fā)事件。在調(diào)用emit()方法時(shí),傳遞了自定義的type參數(shù)。

const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('click', (type) => {
  console.log(`觸發(fā)${type}事件`);
});
myEmitter.emit('click', "點(diǎn)擊");

?? 可注冊(cè)多個(gè)相同名稱的事件,監(jiān)聽(tīng)器會(huì)按照添加順序依次調(diào)用。事件模塊還提供了很多其它方法,例如 off() 用于解除事件綁定,once() 可以只監(jiān)聽(tīng)一次事件。

總結(jié)

本節(jié)介紹了 Nodejs 中 Buffer對(duì)象 的一些具體使用方法和說(shuō)明,并借此提及 Stream 的相關(guān)內(nèi)容,之后我將介紹一下 Nodejs 提供的標(biāo)準(zhǔn) I/O 方法,更多關(guān)于Nodejs Buffer Stream流的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • NodeJS 創(chuàng)建目錄和文件的方法實(shí)例分析

    NodeJS 創(chuàng)建目錄和文件的方法實(shí)例分析

    這篇文章主要介紹了NodeJS 創(chuàng)建目錄和文件的方法,涉及node.js中fs模塊mkdir、writeFile及目錄判斷existsSync等方法的功能與相關(guān)使用技巧,需要的朋友可以參考下
    2023-04-04
  • 關(guān)于npm?i幾種常見(jiàn)命令的區(qū)別詳解

    關(guān)于npm?i幾種常見(jiàn)命令的區(qū)別詳解

    npm(Node.js Package Manager)是一個(gè)Node.js的包管理工具,用來(lái)解決Node.js代碼部署問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于npm?i幾種常見(jiàn)命令的那點(diǎn)事,需要的朋友可以參考下
    2023-03-03
  • 用nodeJS搭建本地文件服務(wù)器的幾種方法小結(jié)

    用nodeJS搭建本地文件服務(wù)器的幾種方法小結(jié)

    本篇文章主要介紹了用nodeJS搭建本地文件服務(wù)器的幾種方法小結(jié),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-03-03
  • 如何在 Node.js 中使用 axios 配置代理并實(shí)現(xiàn)圖片并發(fā)下載

    如何在 Node.js 中使用 axios 配置代理并實(shí)現(xiàn)圖片并發(fā)下載

    這篇文章主要介紹了如何在Node.js中使用axios配置代理并實(shí)現(xiàn)圖片并發(fā)下載,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-07-07
  • 基于node.js實(shí)現(xiàn)微信支付退款功能

    基于node.js實(shí)現(xiàn)微信支付退款功能

    在微信開(kāi)發(fā)中有有付款就會(huì)有退款,這樣的功能非常常見(jiàn),這篇文章主要介紹了node.js實(shí)現(xiàn)微信支付退款功能,需要的朋友可以參考下
    2017-12-12
  • Nodejs libuv運(yùn)行原理詳解

    Nodejs libuv運(yùn)行原理詳解

    在本篇文章里小編給大家整理的是關(guān)于Nodejs libuv運(yùn)行原理以及相關(guān)知識(shí)點(diǎn),有需要的朋友們可以學(xué)習(xí)下。
    2019-08-08
  • npm?ERR!?Node.js?v20.11.0錯(cuò)誤的解決

    npm?ERR!?Node.js?v20.11.0錯(cuò)誤的解決

    在使用?npm?進(jìn)行包管理和構(gòu)建項(xiàng)目的過(guò)程中,有時(shí)會(huì)遇到錯(cuò)誤信息?npm?ERR!?Node.js?v20.11.0,本文就來(lái)介紹一下如何解決,感興趣的可以了解一下
    2024-02-02
  • 在nodejs中使用swagger方式

    在nodejs中使用swagger方式

    這篇文章主要介紹了在nodejs中使用swagger方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • Node.js入門筆記?之a(chǎn)sync模塊

    Node.js入門筆記?之a(chǎn)sync模塊

    這篇文章主要介紹了Node.js入門筆記?之a(chǎn)sync模塊,async是一個(gè)異步處理模塊,主要有三個(gè)方式:串行無(wú)關(guān)聯(lián)、并行無(wú)關(guān)聯(lián)?、串行有關(guān)聯(lián),文章圍繞主題展開(kāi)更多的相關(guān)內(nèi)容,需要的小伙伴可以參考一下
    2022-06-06
  • node.js中的fs.readlinkSync方法使用說(shuō)明

    node.js中的fs.readlinkSync方法使用說(shuō)明

    這篇文章主要介紹了node.js中的fs.readlinkSync方法使用說(shuō)明,本文介紹了fs.readlinkSync方法說(shuō)明、語(yǔ)法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下
    2014-12-12

最新評(píng)論