浅析Node.js的Stream模块中的Readable对象


Posted in Javascript onJuly 29, 2015

我一直都很不愿意扯 nodejs 的流,因为从第一次看到它我就觉得它的设计实在是太恶心了。但是没办法,Stream 规范尚未普及,而且确实有很多东西都依赖了 nodejs 的流来实现的,所以我也只能捏着鼻子硬着头皮来扯一扯这又臭又硬的 nodejs 流对象了。

nodejs 自带了一个叫 stream 的模块,引入它便可以得到一组流对象构造器。现在我只说最简单的 stream.Readable。

其实用过 nodejs 的几乎都接触过 Readable 的实例,只是平时没太在意而已。一个非常典型的例子,http 模块中我们处理每个请求时都会有 req 和 res 对象,req 其实就是一个 Readable 对象。我们可以在这个 req 上以流的形式读到 HTTP 请求的实体部分。

那么问题来了,为什么 http 模块要在此处以流的方式设计呢?或者从另一个维度来问这个问题就是「nodejs 如果获取 POST 请求的内容?」。懂得用搜索引擎的同学肯定可以很容易地找到这么一个答案:监听 data 事件收集数据,在 end 事件中把收集到的数据合并起来。是的,这是解决这个问题的方法。但是为什么它如此设计呢?像 PHP 那样直接就可以取到 POST 内容多好?其实这么设计是有好处的,如果我们接收到的数据是非法的,我可以马上察觉,然后响应并断开连接。这样可以避免一些不必要的传输成本。比如上传图片,也许用户错误地选择了一个很大的可执行文件,我们不需要等到这个文件完全上传完毕,只要一个文件头部的若干字节就能判断一个文件是否是图片了。此处使用流的设计就可以先读出前面的几个字节来使用。

上面提到的 data 事件和 end 事件都是 Readable 的事件,这两个事件分别表示收到数据和数据接收完毕。所以其实我们早已知道了 Readable 的用法,只是很多人不知道它是 Readable 对象而已。

但是上面这两个事件仅仅是对 Readable 的消费者而言的事件。内部是如何把一个数据推送到 Readable 对象里面让 Readable 触发出这些事件的呢?那么它就是 push 方法。下面是一个例子,它创建了一个 Readable 对象,这个对象会流出一个递增的数字(这里使用了 babel-node)

import stream from 'stream';

var r = new stream.Readable;

r.on('data', data => {
 console.log(data + '');
});

r.on('end', data => {
 console.log('end');
});

r._read = () => {
 // console.log('before read');
};

void function callee(i) {
 if(i < 10) {
  r.push(i + ''); // 只能传入字符串或 Buffre 对象
 } else {
  r.push(null); // 当输入一个 null 时表示流传输完成,触发 end 事件 
 }
 setTimeout(callee, 500, i + 1);
}(0);

如果仔细看上面代码就会发现一个很神奇的地方,这个代码覆写了 _read 方法,这是什么鬼?其实我也觉得这是个坑,这个私有命名风格就不吐槽了,为何非要覆写这个方法才算实现它?如果没有覆写这个方法,那么在调用 push 时将抛出异常:

Error: not implemented
  at Readable._read (_stream_readable.js:464:22)
  at Readable.read (_stream_readable.js:341:10)

以上这些便是 Readable 对象的基本用法。但是还有更多坑会踩到,这篇文章只是一个最简单的介绍,让大家学会如何造出一个能输出数据的 Readable 对象而已。至于一些 read 之类的基本方法,反正这些也是不科学的设计之一。

Javascript 相关文章推荐
JS数学函数Exp使用说明
Aug 09 Javascript
javascript与cookie 的问题详解
Nov 11 Javascript
javascript/jquery获取地址栏url参数的方法
Mar 05 Javascript
jQuery实现伪分页的方法分享
Feb 17 Javascript
利用JQuery写一个简单的异步分页插件
Mar 07 Javascript
详解JavaScript异步编程中jQuery的promise对象的作用
May 03 Javascript
ES6新特性五:Set与Map的数据结构实例分析
Apr 21 Javascript
vue自定义全局组件(自定义插件)的用法
Jan 30 Javascript
JS常用的几种数组遍历方式以及性能分析对比实例详解
Apr 11 Javascript
用JS实现根据当前时间随机生成流水号或者订单号
May 31 Javascript
Node.js命令行/批处理中如何更改Linux用户密码浅析
Jul 22 Javascript
vue-cli3使用mock数据的方法分析
Mar 16 Javascript
浅谈Javascript数组的使用
Jul 29 #Javascript
举例讲解Node.js中的Writable对象
Jul 29 #Javascript
浅谈Javascript数组索引
Jul 29 #Javascript
JQ实现新浪游戏首页幻灯片
Jul 29 #Javascript
JavaScript中几种排序算法的简单实现
Jul 29 #Javascript
详解JavaScript中数组的相关知识
Jul 29 #Javascript
javascript+canvas实现刮刮卡抽奖效果
Jul 29 #Javascript
You might like
PHP弹出对话框技巧详细解读
2015/09/26 PHP
PHP实现中国公民身份证号码有效性验证示例代码
2017/05/03 PHP
Array对象方法参考
2006/10/03 Javascript
一段多浏览器的&quot;复制到剪贴板&quot;javascript代码
2007/03/27 Javascript
HTML node相关的一些资料整理
2010/01/01 Javascript
jQuery UI 实现email输入提示实例
2013/08/15 Javascript
JavaScript中的值类型详细介绍
2014/12/29 Javascript
javascript判断图片是否加载完成的方法推荐
2016/05/13 Javascript
jQuery控制文本框只能输入数字和字母及使用方法
2016/05/26 Javascript
vuex 项目结构目录及一些简单配置介绍
2018/04/08 Javascript
JS同步、异步、延迟加载的方法
2018/05/05 Javascript
vue-cli脚手架build目录下utils.js工具配置文件详解
2018/09/14 Javascript
Weex开发之地图篇的具体使用
2019/10/16 Javascript
解决Vue-cli3没有vue.config.js文件夹及配置vue项目域名的问题
2020/12/04 Vue.js
[00:35]可解锁地面特效
2018/12/20 DOTA
[01:13:18]Secret vs Infamous 2019国际邀请赛淘汰赛 败者组 BO3 第一场 8.23
2019/09/05 DOTA
Python实现统计文本文件字数的方法
2017/05/05 Python
tornado 多进程模式解析
2018/01/15 Python
python语言中with as的用法使用详解
2018/02/23 Python
Python 编程速成(推荐)
2019/04/15 Python
python关于矩阵重复赋值覆盖问题的解决方法
2019/07/19 Python
python正则表达式匹配IP代码实例
2019/12/28 Python
Python优秀开源项目Rich源码解析的流程分析
2020/07/06 Python
记一次python 爬虫爬取深圳租房信息的过程及遇到的问题
2020/11/24 Python
美国第二大连锁书店:Books-A-Million
2017/12/28 全球购物
英国领先的杂志订阅网站:Magazine.co.uk
2018/01/25 全球购物
如何估计一张表的大小(假设该表中有1万条数据)
2016/03/27 面试题
清明节网上祭英烈活动总结
2014/04/30 职场文书
创建文明城市标语
2014/06/16 职场文书
大型公益活动策划方案
2014/08/20 职场文书
2014市国税局对照检查材料思想汇报
2014/09/23 职场文书
幸福家庭事迹材料
2014/12/20 职场文书
开会通知
2015/04/20 职场文书
水知道答案观后感
2015/06/08 职场文书
获奖感言一句话
2015/07/31 职场文书
《勇者辞职不干了》上卷BD发售宣传CM公开
2022/04/08 日漫