前面的話

  當(dāng)內(nèi)存中無(wú)法一次裝下需要處理的數(shù)據(jù)時(shí),或者一邊讀取一邊處理更加高效時(shí),我們就需要用到數(shù)據(jù)流。NodeJS中通過(guò)各種Stream來(lái)提供對(duì)數(shù)據(jù)流的操作。本文將詳細(xì)說(shuō)明NodeJS中的流stream

 

概述

  流(stream)在Nodejs中是處理流數(shù)據(jù)的抽象接口。stream模塊提供了基礎(chǔ)的API 。使用這些API可以很容易地來(lái)構(gòu)建實(shí)現(xiàn)流接口的對(duì)象。Nodejs提供了多種流對(duì)象。 例如,HTTP請(qǐng)求和process.stdout都是流的實(shí)例

  流可以是可讀的、可寫(xiě)的,或是可讀寫(xiě)的。所有的流都是 EventEmitter 的實(shí)例。

  盡管所有的 Node.js 用戶都應(yīng)該理解流的工作方式,這點(diǎn)很重要, 但是 stream 模塊本身只對(duì)于那些需要?jiǎng)?chuàng)建新的流的實(shí)例的開(kāi)發(fā)者最有用處。 對(duì)于主要是消費(fèi)流的開(kāi)發(fā)者來(lái)說(shuō),他們很少(如果有的話)需要直接使用 stream 模塊

【類型】

  Node.js 中有四種基本的流類型:

Readable - 可讀的流 (例如 fs.createReadStream()).
Writable - 可寫(xiě)的流 (例如 fs.createWriteStream()).
Duplex - 可讀寫(xiě)的流 (例如 net.Socket).
Transform - 在讀寫(xiě)過(guò)程中可以修改和變換數(shù)據(jù)的 Duplex 流 (例如 zlib.createDeflate()).

  所有使用 Node.js API 創(chuàng)建的流對(duì)象都只能操作 strings 和 Buffer(或 Uint8Array) 對(duì)象。但是,通過(guò)一些第三方流的實(shí)現(xiàn),依然能夠處理其它類型的 JavaScript 值 (除了 null,它在流處理中有特殊意義)。 這些流被認(rèn)為是工作在 “對(duì)象模式”(object mode)

  在創(chuàng)建流的實(shí)例時(shí),可以通過(guò) objectMode 選項(xiàng)使流的實(shí)例切換到對(duì)象模式。試圖將已經(jīng)存在的流切換到對(duì)象模式是不安全的

【緩沖】

  Writable和Readable流都會(huì)將數(shù)據(jù)存儲(chǔ)到內(nèi)部的緩存(buffer)中。這些緩存可以通過(guò)相應(yīng)的writable._writableState.getBuffer()或readable._readableState.buffer來(lái)獲取

  緩存的大小取決于傳遞給流構(gòu)造函數(shù)的highWaterMark選項(xiàng)。 對(duì)于普通的流,highWaterMark選項(xiàng)指定了總共的字節(jié)數(shù)。對(duì)于工作在對(duì)象模式的流,highWaterMark指定了對(duì)象的總數(shù)

  當(dāng)可讀流的實(shí)現(xiàn)調(diào)用stream.push(chunk)方法時(shí),數(shù)據(jù)被放到緩存中。如果流的消費(fèi)者沒(méi)有調(diào)用stream.read()方法, 這些數(shù)據(jù)會(huì)始終存在于內(nèi)部隊(duì)列中,直到被消費(fèi)

  當(dāng)內(nèi)部可讀緩存的大小達(dá)到highWaterMark指定的閾值時(shí),流會(huì)暫停從底層資源讀取數(shù)據(jù),直到當(dāng)前緩存的數(shù)據(jù)被消費(fèi)(也就是說(shuō),流會(huì)在內(nèi)部停止調(diào)用readable._read()來(lái)填充可讀緩存)

  可寫(xiě)流通過(guò)反復(fù)調(diào)用writable.write(chunk)方法將數(shù)據(jù)放到緩存。當(dāng)內(nèi)部可寫(xiě)緩存的總大小小于highWaterMark指定的閾值時(shí),調(diào)用writable.write()將返true。 一旦內(nèi)部緩存的大小達(dá)到或超過(guò)highWaterMark,調(diào)用writable.write()將返回false

  stream API 的關(guān)鍵目標(biāo), 尤其對(duì)于 stream.pipe() 方法, 就是限制緩存數(shù)據(jù)大小,以達(dá)到可接受的程度。這樣,對(duì)于讀寫(xiě)速度不匹配的源頭和目標(biāo),就不會(huì)超出可用的內(nèi)存大小。

  Duplex和Transform都是可讀寫(xiě)的。 在內(nèi)部,它們都維護(hù)了兩 相互獨(dú)立的緩存用于讀和寫(xiě)。 在維持了合理高效的數(shù)據(jù)流的同時(shí),也使得對(duì)于讀和寫(xiě)可以獨(dú)立進(jìn)行而互不影響。 例如, net.Socket就是Duplex的實(shí)例,它的可讀端可以消費(fèi)從套接字(socket)中接收的數(shù)據(jù), 可寫(xiě)端則可以將數(shù)據(jù)寫(xiě)入到套接字。 由于數(shù)據(jù)寫(xiě)入到套接字中的速度可能比從套接字接收數(shù)據(jù)的速度快或者慢, 在讀寫(xiě)兩端使用獨(dú)立緩存,并進(jìn)行獨(dú)立操作就顯得很重要了

  幾乎所有的 Node.js 應(yīng)用,不管多么簡(jiǎn)單,都在某種程度上使用了流。 下面是在 Node.js 應(yīng)用中使用流實(shí)現(xiàn)的一個(gè)簡(jiǎn)單的 HTTP 服務(wù)器

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

var http = require('http');var server = http.createServer((req, res) => {  // req 是一個(gè) Readable Stream;res 是一個(gè) Writable Stream
  var body = '';
  req.setEncoding('utf8');
  req.on('data', (chunk) => {
    body += chunk;
  });
  req.on('end', () => {    try {      var data = JSON.parse(body);
      res.write(typeof data);
      res.end();
    } catch (er) {
      res.statusCode = 400;      return res.end(`error: ${er.message}`);
    }
  });
});
server.listen(1337);

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

  Writable 流 (比如例子中的 res) 暴露了一些方法,比如 write() 和 end() 。這些方法可以將數(shù)據(jù)寫(xiě)入到流中。當(dāng)流中的數(shù)據(jù)可以讀取時(shí),Readable 流使用 EventEmitter API 來(lái)通知應(yīng)用。 這些數(shù)據(jù)可以使用多種方法從流中讀取。Writable 和 Readable 流都使用了 EventEmitter API ,通過(guò)多種方式, 與流的當(dāng)前狀態(tài)進(jìn)行交互。Duplex 和 Transform 都是同時(shí)滿足 Writable 和 Readable 。對(duì)于只是簡(jiǎn)單寫(xiě)入數(shù)據(jù)到流和從流中消費(fèi)數(shù)據(jù)的應(yīng)用來(lái)說(shuō), 不要求直接實(shí)現(xiàn)流接口,通常也不需要調(diào)用 require('stream')

 

可寫(xiě)流

  可寫(xiě)流是對(duì)數(shù)據(jù)流向設(shè)備的抽象,用來(lái)消費(fèi)上游流過(guò)來(lái)的數(shù)據(jù),通過(guò)可寫(xiě)流程序可以把數(shù)據(jù)寫(xiě)入設(shè)備,常見(jiàn)的是本地磁盤(pán)文件或者 TCP、HTTP 等網(wǎng)絡(luò)響應(yīng)

process.stdin.pipe(process.stdout);

  process.stdout是一個(gè)可寫(xiě)流,程序把可讀流 process.stdin 傳過(guò)來(lái)的數(shù)據(jù)寫(xiě)入的標(biāo)準(zhǔn)輸出設(shè)備

  Writable(可寫(xiě)流)包括:

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

HTTP requests, on the client
HTTP responses, on the server
fs write streams
[zlib streams][zlib]
crypto streams
TCP sockets
child process stdin
process.stdout, process.stderr

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

  [注意]上面的某些例子事實(shí)上是 Duplex 流,只是實(shí)現(xiàn)了 Writable 接口

  所有 Writable 流都實(shí)現(xiàn)了 stream.Writable 類定義的接口。盡管特定的 Writable 流的實(shí)現(xiàn)可能略有差別, 所有的 Writable streams 都可以按一種基本模式進(jìn)行使用

var myStream = getWritableStreamSomehow();
myStream.write('some data');
myStream.write('some more data');
myStream.end('done writing data');

【'close' 事件】

  'close'事件將在流或其底層資源(比如一個(gè)文件)關(guān)閉后觸發(fā)。'close'事件觸發(fā)后,該流將不會(huì)再觸發(fā)任何事件

  [注意]不是所有可寫(xiě)流都會(huì)觸發(fā) 'close' 事件

【'drain' 事件】

  如果調(diào)用 stream.write(chunk) 方法返回 false,流將在適當(dāng)?shù)臅r(shí)機(jī)觸發(fā) 'drain' 事件,這時(shí)才可以繼續(xù)向流中寫(xiě)入數(shù)據(jù)

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

// 向可寫(xiě)流中寫(xiě)入數(shù)據(jù)一百萬(wàn)次。// 需要注意背壓(back-pressure)function writeOneMillionTimes(writer, data, encoding, callback) {
  let i = 1000000;
  write();  function write() {
    let ok = true;    do {
      i--;      if (i === 0) {        // 最后 一次        writer.write(data, encoding, callback);
      } else {        // 檢查是否可以繼續(xù)寫(xiě)入。 
        // 這里不要傳遞 callback, 因?yàn)閷?xiě)入還沒(méi)有結(jié)束! 
        ok = writer.write(data, encoding);
      }
    } while (i > 0 && ok);    if (i > 0) {      // 這里提前停下了, 
      // 'drain' 事件觸發(fā)后才可以繼續(xù)寫(xiě)入  
      writer.once('drain', write);
    }
  }
}

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

【'error' 事件】

  'error' 事件在寫(xiě)入數(shù)據(jù)出錯(cuò)或者使用管道出錯(cuò)時(shí)觸發(fā)。事件發(fā)生時(shí),回調(diào)函數(shù)僅會(huì)接收到一個(gè) Error 參數(shù)

  [注意]'error' 事件發(fā)生時(shí),流并不會(huì)關(guān)閉

【'finish' 事件】

  在調(diào)用了 stream.end() 方法,且緩沖區(qū)數(shù)據(jù)都已經(jīng)傳給底層系統(tǒng)(underlying system)之后, 'finish' 事件將被觸發(fā)

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

const writer = getWritableStreamSomehow();for (let i = 0; i < 100; i++) {
  writer.write(`hello, #${i}!\n`);
}
writer.end('This is the end\n');
writer.on('finish', () => {
  console.error('All writes are now complete.');
});

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

【'pipe' 事件】

src <stream.Readable> 輸出到目標(biāo)可寫(xiě)流(writable)的源流(source stream)

  在可讀流(readable stream)上調(diào)用 stream.pipe() 方法,并在目標(biāo)流向 (destinations) 中添加當(dāng)前可寫(xiě)流 ( writable ) 時(shí),將會(huì)在可寫(xiě)流上觸發(fā) 'pipe' 事件

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

const writer = getWritableStreamSomehow();
const reader = getReadableStreamSomehow();
writer.on('pipe', (src) => {
  console.error('something is piping into the writer');
  assert.equal(src, reader);
});
reader.pipe(writer);

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

【'unpipe' 事件】

src <Readable Stream> unpiped 當(dāng)前可寫(xiě)流的源流

  在 Readable 上調(diào)用 stream.unpipe() 方法,從目標(biāo)流向中移除當(dāng)前 Writable 時(shí),將會(huì)觸發(fā) 'unpipe' 事件

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

const writer = getWritableStreamSomehow();
const reader = getReadableStreamSomehow();
writer.on('unpipe', (src) => {
  console.error('Something has stopped piping into the writer.');
  assert.equal(src, reader);
});
reader.pipe(writer);
reader.unpipe(writer);

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

【writable.cork()】

  調(diào)用 writable.cork() 方法將強(qiáng)制所有寫(xiě)入數(shù)據(jù)都內(nèi)存中的緩沖區(qū)里。 直到調(diào)用 stream.uncork() 或 stream.end() 方法時(shí),緩沖區(qū)里的數(shù)據(jù)才會(huì)被輸出

  在向流中寫(xiě)入大量小塊數(shù)據(jù)(small chunks of data)時(shí),內(nèi)部緩沖區(qū)(internal buffer)可能失效,從而導(dǎo)致性能下降。writable.cork() 方法主要就是用來(lái)避免這種情況。 對(duì)于這種情況, 實(shí)現(xiàn)了 writable._writev() 方法的流可以對(duì)寫(xiě)入的數(shù)據(jù)進(jìn)行緩沖,從而提高寫(xiě)入效率

【writable.end([chunk][, encoding][, callback])】

chunk <string> | <Buffer> | <Uint8Array> | <any>
chunk <string> | <Buffer> | <Uint8Array> | <any> 可選的,需要寫(xiě)入的數(shù)據(jù)。對(duì)于非對(duì)象模式下的流, chunk 必須是字符串、或 Buffer、或 Uint8Array。對(duì)于對(duì)象模式下的流, chunk 可以是任意的 JavaScript 值,除了 null。
encoding <string> 如果 chunk 是字符串,這里指定字符編碼。
callback <Function> 可選的,流結(jié)束時(shí)的回調(diào)函數(shù)

  調(diào)用 writable.end() 方法表明接下來(lái)沒(méi)有數(shù)據(jù)要被寫(xiě)入 Writable。通過(guò)傳入可選的 chunk 和 encoding 參數(shù),可以在關(guān)閉流之前再寫(xiě)入一段數(shù)據(jù)。如果傳入了可選的 callback 函數(shù),它將作為 'finish' 事件的回調(diào)函數(shù)。

  [注意]在調(diào)用了 stream.end() 方法之后,再調(diào)用 stream.write() 方法將會(huì)導(dǎo)致錯(cuò)誤

// 寫(xiě)入 'hello, ' ,并用 'world!' 來(lái)結(jié)束寫(xiě)入const file = fs.createWriteStream('example.txt');
file.write('hello, ');
file.end('world!');// 后面不允許再寫(xiě)入數(shù)據(jù)!

【writable.setDefaultEncoding(encoding)】

encoding <string> 新的默認(rèn)編碼
返回: this

  writable.setDefaultEncoding() 用于為 Writable 設(shè)置 encoding

【writable.uncork()】

  writable.uncork() 將輸出在 stream.cork() 方法被調(diào)用之后緩沖在內(nèi)存中的所有數(shù)據(jù)

  如果使用 writable.cork() 和 writable.uncork() 來(lái)管理寫(xiě)入緩存,建議使用 process.nextTick() 來(lái)延遲調(diào)用 writable.uncork() 方法。通過(guò)這種方式,可以對(duì)單個(gè) Node.js 事件循環(huán)中調(diào)用的所有 writable.write() 方法進(jìn)行批處理

stream.cork();
stream.write('some ');
stream.write('data ');
process.nextTick(() => stream.uncork());

  如果一個(gè)流多次調(diào)用了 writable.cork() 方法,那么也必須調(diào)用同樣次數(shù)的 writable.uncork() 方法以輸出緩沖區(qū)數(shù)據(jù)

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

stream.cork();
stream.write('some ');
stream.cork();
stream.write('data ');
process.nextTick(() => {
  stream.uncork();  // 之前的數(shù)據(jù)只有在 uncork() 被二次調(diào)用后才會(huì)輸出  stream.uncork();
});

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

【writable.write(chunk[, encoding][, callback])】

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

chunk <string> | <Buffer> | <Uint8Array> | <any> 要寫(xiě)入的數(shù)據(jù)??蛇x的。 For streams not operating in object mode, chunk must be a string, Buffer or Uint8Array. For object mode streams, chunk may be any JavaScript value other than null.
encoding <string> 如果 chunk 是字符串,這里指定字符編碼
callback <Function> 緩沖數(shù)據(jù)輸出時(shí)的回調(diào)函數(shù)
返回: <boolean> 如果流需要等待 'drain' 事件觸發(fā)才能繼續(xù)寫(xiě)入數(shù)據(jù),這里將返回 false ; 否則返回 true。

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

  writable.write() 方法向流中寫(xiě)入數(shù)據(jù),并在數(shù)據(jù)處理完成后調(diào)用 callback 。如果有錯(cuò)誤發(fā)生, callback不一定會(huì)接收到這個(gè)錯(cuò)誤作為第一個(gè)參數(shù)。要確??煽康貦z測(cè)到寫(xiě)入錯(cuò)誤,應(yīng)該監(jiān)聽(tīng) 'error' 事件。

  在確認(rèn)了 chunk 后,如果內(nèi)部緩沖區(qū)的大小小于創(chuàng)建流時(shí)設(shè)定的 highWaterMark 閾值,函數(shù)將返回 true 。 如果返回值為 false ,應(yīng)該停止向流中寫(xiě)入數(shù)據(jù),直到 'drain' 事件被觸發(fā)。

  當(dāng)一個(gè)流不處在 drain 的狀態(tài), 對(duì) write() 的調(diào)用會(huì)緩存數(shù)據(jù)塊, 并且返回 false。 一旦所有當(dāng)前所有緩存的數(shù)據(jù)塊都排空了(被操作系統(tǒng)接受來(lái)進(jìn)行輸出), 那么 'drain' 事件就會(huì)被觸發(fā)。 我們建議, 一旦 write() 返回 false, 在 'drain' 事件觸發(fā)前, 不能寫(xiě)入任何數(shù)據(jù)塊。 然而,當(dāng)流不處在 'drain' 狀態(tài)時(shí), 調(diào)用 write() 是被允許的, Node.js 會(huì)緩存所有已經(jīng)寫(xiě)入的數(shù)據(jù)塊, 直到達(dá)到最大內(nèi)存占用, 這時(shí)它會(huì)無(wú)條件中止。 甚至在它中止之前, 高內(nèi)存占用將會(huì)導(dǎo)致差的垃圾回收器的性能和高的系統(tǒng)相對(duì)敏感性 (即使內(nèi)存不在需要,也通常不會(huì)被釋放回系統(tǒng))。 如果遠(yuǎn)程的另一端沒(méi)有讀取數(shù)據(jù), TCP sockets 可能永遠(yuǎn)也不會(huì) drain , 所以寫(xiě)入到一個(gè)不會(huì)drain的socket可能會(huì)導(dǎo)致遠(yuǎn)程可利用的漏洞。

  對(duì)于一個(gè) Transform, 寫(xiě)入數(shù)據(jù)到一個(gè)不會(huì)drain的流尤其成問(wèn)題, 因?yàn)?Transform 流默認(rèn)被暫停, 直到它們被pipe或者被添加了 'data' 或 'readable' event handler。

  如果將要被寫(xiě)入的數(shù)據(jù)可以根據(jù)需要生成或者取得,我們建議將邏輯封裝為一個(gè) Readable 流并且使用 stream.pipe()。 但是如果調(diào)用 write() 優(yōu)先, 那么可以使用 'drain' 事件來(lái)防止回壓并且避免內(nèi)存問(wèn)題:

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

function write(data, cb) {  if (!stream.write(data)) {
    stream.once('drain', cb);
  } else {
    process.nextTick(cb);
  }
}// Wait for cb to be called before doing any other write.write('hello', () => {
  console.log('write completed, do more writes now');
});

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

  [注意]對(duì)象模式的寫(xiě)入流將忽略 encoding 參數(shù)

【writable.destroy([error])】

  銷毀流,并釋放已傳遞的錯(cuò)誤。在這之后,可寫(xiě)的流已經(jīng)結(jié)束了。實(shí)現(xiàn)者不應(yīng)該覆蓋此方法,而是實(shí)現(xiàn)writable._destroy

 

可讀流

  可讀流(Readable streams)是對(duì)提供數(shù)據(jù)的源頭(source)的抽象,是生產(chǎn)數(shù)據(jù)用來(lái)供程序消費(fèi)的流。我們常見(jiàn)的數(shù)據(jù)生產(chǎn)方式有讀取磁盤(pán)文件、讀取網(wǎng)絡(luò)請(qǐng)求內(nèi)容等

const rs = fs.createReadStream(filePath);

  rs就是一個(gè)可讀流,其生產(chǎn)數(shù)據(jù)的方式是讀取磁盤(pán)的文件,我們常見(jiàn)的控制臺(tái)process.stdin也是一個(gè)可讀流

process.stdin.pipe(process.stdout);

  通過(guò)簡(jiǎn)單的一句話可以把控制臺(tái)的輸入打印出來(lái),process.stdin 生產(chǎn)數(shù)據(jù)的方式是讀取用戶在控制臺(tái)的輸入

  可讀流的例子包括:

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

HTTP responses, on the client
HTTP requests, on the server
fs read streams
[zlib streams][zlib]
crypto streams
TCP sockets
child process stdout and stderr
process.stdin

電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),Web培訓(xùn),Web前端開(kāi)發(fā)培訓(xùn)

  [注意]所有的 Readable 都實(shí)現(xiàn)了 stream.Readable 類定義的接口

【兩種模式】

  可讀流事實(shí)上工作在下面兩種模式之一:flowing 和 paused 。

  在flowing模式下,可讀流自動(dòng)從系統(tǒng)底層讀取數(shù)據(jù),并通過(guò)EventEmitter接口的事件盡快將數(shù)據(jù)提供給應(yīng)用

  在paused模式下,必須顯式調(diào)用 stream.read() 方法來(lái)從流中讀取數(shù)據(jù)片段。

  所有初始工作模式為 paused 的 Readable 流,可以通過(guò)下面三種途徑切換到 flowing 模式:

監(jiān)聽(tīng) 'data' 事件。
調(diào)用 stream.resume() 方法。
調(diào)用 stream.pipe() 方法將數(shù)據(jù)發(fā)送到 Writable。

  可讀流可以通過(guò)下面途徑切換到 paused 模式:

http://www.cnblogs.com/xiaohuochai/p/6969307.html