前言:
什么?砖升本?不行,戒毒后只想学习代码。跟随Geemo狗的节奏,学习下他的stream深入篇,好的直接略过博文看最后的参考资料 ,美团前端的文章,那么我就跟随着来上那么一发。
美团原文: http://fe.meituan.com/stream-internals.html
流的应用:
先来一发,我写了个复制java学习资料的栗子。代码如下。(知乎上有参考),clearLine,cursorTo等方法已经从process.stdout移到了Readline那里,具体可以看极客的API或者英文API。
"use strict" const readline = require('readline'); const fs = require('fs'); const filePath = 'snis716.avi'; const reFilePath = 'javlibrary.avi'; let passedLength = 0; let lastSize = 0; let readStream = fs.createReadStream(filePath); let writeStream = fs.createWriteStream(reFilePath); //返回stat数组 let stat=fs.statSync(filePath); const totalSize=stat.size; console.log(stat); readStream.on('data',chunk =>{ passedLength+= chunk.length; if(writeStream.write(chunk) === false ){ readStream.pause(); } }) readStream.on('end', ()=> { writeStream.end(); }) //drain事件:可以向流中写入更多数据 writeStream.on('drain', ()=> { readStream.resume();//继续触发data }) console.info(`正在复制${filePath}到${reFilePath}`); console.time('copyTime'); setTimeout(function show() { let present = Math.ceil((passedLength/totalSize)*100); let size = Math.ceil((passedLength/1048576)); let currentSize = size - lastSize; lastSize = size; //清除本行 readline.clearLine(process.stdout, 0) //光标移向本行初始位置 readline.cursorTo(process.stdout, 0, null) process.stdout.write(`正在复制,写入速率${currentSize*2}MB/s,已写入${size}MB`); if (passedLength < totalSize) { setTimeout(show, 500); } else { console.log('\n'); console.timeEnd('copyTime'); }},500)
这段代码就复制了G级文件,当然也可以用pipe 实现自动控制。
fs.createReadStream(‘snis716.avi’).pipe(fs.createWriteStream(‘javlibrary.avi’));
Stream 潜入
先上API http://nodeapi.ucdok.com/#/api/stream.html
var Stream = require(‘stream’);
var Readable = Stream.Readable;//可读流
var Writable = Stream.Writable;//可写流
var Duplex = Stream.Duplex;//可读可写流
var Transform = Stream.Transform;//因果关系的双工流
var Readable = Stream.Readable;//可读流
var Writable = Stream.Writable;//可写流
var Duplex = Stream.Duplex;//可读可写流
var Transform = Stream.Transform;//因果关系的双工流
Readable:
下游请求数据,会调用_read()方法,这东西一方面从数据源获取数据,一方面Push并触发data事件。
Read实现:
//Readable局部源码 var doRead = state.needReadable; // if we currently have less than the highWaterMark, then also read some if (state.length === 0 || state.length - n < state.highWaterMark) { doRead = true; } if (state.ended || state.reading) { doRead = false; debug('reading or ended', doRead); } if (doRead) { debug('do read'); state.reading = true; state.sync = true; if (state.length === 0) state.needReadable = true; // call internal read method this._read(state.highWaterMark); state.sync = false; } // 如果_read是同步的那么reading为false // 从缓存获取的实际数据量 if (doRead && !state.reading){ n = howMuchToRead(nOrig, state); state.sync = false }
state.highWaterMark 缓存阈值
state.length 当前缓存数据量
state.flowing 流动模式
sync push方法的同/异步
state.needReadable 缓存是否充足,不充足从底层来数据
reading 上一次从底层获取数据是否结束
后记
今天到这了,记录下,后面的内容看Geemo和美团了,懒得码字了,还是这是别人理解出来的东西,接下来就要自己看源码,结合下别人的理解,去“看懂”源码了。有时候了解个原理过程很简单,但是能设计并应用上去却很难,剩下的看源码了,我这就不重复搬弄了。