作爲一個前端猿,一直對後端天天能夠任性的操做服務器文件感到羨慕。最近學習node的fs模塊玩的也是意猶未盡好不知足。fs.readFile方法在讀取大文件時沒法勝任,因此流出現了。前端
個人理解 咱們在網上下載資源時,稍微大一點就要下載個把小時。咱們的帶寬遠遠不能知足從服務端把資源整個端走,因此要把資源拆分紅小塊,一塊一塊的運輸。資源就像水同樣流到了咱們本地。node
While it is important for all Node.js users to understand how streams work.(官網說流很重要!)後端
nodejs有四種基本的流類型:緩存
可讀流的功能是做爲上游,提供數據給下游。bash
let {Readable} = require('stream');
let readable = Readable();
/*
Readable({read(){})
*/
let source = ['a','b','c'];
readable.setEncoding('utf8');
readable._read = function () {
let data = source.shift()||null;
console.log('read:',data);
this.push(data);
}
readable.on('end', function () {
console.log('end')
})
readable.on('data', function (data) {
console.log(data)
})
/*
輸出:
read: a
read: b
a
read: c
b
read: null
c
end
*/
複製代碼
Readable經過實例_read或read方法,在須要數據時,_read()方法會自動調用。服務器
data事件:當讀入數據時觸發data事件傳入回調讀到內容。
end事件:「消耗完」,須要知足兩個條件:異步
flowing 模式下, 可讀流自動從系統底層讀取數據,並經過 EventEmitter 接口的事件儘快將數據提供給應用。
如下條件都可以使readable進入flowing模式:函數
paused 模式下,必須顯式調用 stream.read() 方法來從流中讀取數據片斷。
可讀流能夠經過下面途徑切換到 paused 模式:學習
深刻理解readable
衆所周知node i/o操做一般採用異步操做。在讀取數據時會把數據寫入緩存區。ui
在建立流時,會設置一個highWaterMark參數建立最高水位線。
var stream = require('stream');
var util = require('util');
util.inherits(Counter, stream.Readable);
function Counter(options) {
stream.Readable.call(this, options);
this._index = 0;
}
Counter.prototype._read = function() {
if(this._index++<3){
this.push(this._index+'');
}else{
this.push(null);
}
};
var counter = new Counter();
counter.on('data', function(data){
console.log("讀到數據: " + data.toString());//no maybe
});
counter.on('end', function(data){
console.log("讀完了");
});
複製代碼
可寫流是對數據寫入'目的地'的一種抽象。可寫流的功能是做爲下游,消耗上游提供的數據。
let {Writable} = require('stream');
var writable = Writable({
write: function (data,_,next) {
console.log(data);
next&&next();
}
})
/*
Writable._write(data,_,next)
*/
writable.write('a');
writable.write('b');
writable.write('c');
writable.end();
/*
<Buffer 61>
<Buffer 62>
<Buffer 63>
*/
複製代碼
var stream = require('stream');
var util = require('util');
util.inherits(Writer, stream.Writable);
let stock = [];
function Writer(opt) {
stream.Writable.call(this, opt);
}
Writer.prototype._write = function(chunk, encoding, callback) {
setTimeout(()=>{
stock.push(chunk.toString('utf8'));
console.log("增長: " + chunk);
callback();
},500)
};
var w = new Writer();
for (var i=1; i<=5; i++){
w.write("項目:" + i, 'utf8');
}
w.end("結束寫入",function(){
console.log(stock);
});
複製代碼
從readable讀出數據,writeable寫入數據
const stream = require('stream')
var index = 0;
const readable = stream.Readable({
highWaterMark: 2,
read: function () {
process.nextTick(() => {
console.log('push', ++index)
this.push(index+'');
})
}
})
const writable = stream.Writable({
highWaterMark: 2,
write: function (chunk, encoding, next) {
console.log('寫入:', chunk.toString())
}
})
readable.pipe(writable);
複製代碼
const {Duplex} = require('stream');
const inoutStream = new Duplex({
write(chunk, encoding, callback) {
console.log(chunk.toString());
callback();
},
read(size) {
this.push((++this.index)+'');
if (this.index > 3) {
this.push(null);
}
}
});
inoutStream.index = 0;
process.stdin.pipe(inoutStream).pipe(process.stdout);
複製代碼
const {Transform} = require('stream');
const upperCase = new Transform({
transform(chunk, encoding, callback) {
this.push(chunk.toString().toUpperCase());
callback();
}
});
process.stdin.pipe(upperCase).pipe(process.stdout);
/*
實現大小寫轉換
inpt: a
A
*/
複製代碼
最近在學習nodejs,通過整理寫下學習筆記。歡迎同窗溝通學習心得,若有錯誤的地方也歡迎指正。