在Node.js中使用Javascript Generators详解


Posted in Javascript onMay 05, 2016

Generators是Javascript的一种协同程序( coroutine 简称:协程)风格,是指那些可以在执行时暂停然后又恢复的函数,该函数是在functi配以星号符号形式如function* ,函数内有些特征关键词如yield 和yield*。

function* generatorFn () {

 console.log('look ma I was suspended')

}

var generator = generatorFn() // [1]

setTimeout(function () {

 generator.next() // [2]

}, 2000)

对代码中标注的[1]和[2]解释如下:

1. 这是一个generator以暂停方式开始. 这时没有控制台输出。

2.通过调用其next()方法,这个generator才会执行,运行直至它碰到下一个yield关键词或return,现在我们就有了控制台输出。

再看一个案例:

function *generator() {

 console.log('Start!');

 var i = 0;

 while (true) {

  if (i < 3)

   yield i++;

 }

}
var gen = generator();

以上这段代码类似第一个,只是在generator函数中多了yield关键词,以上这段代码被调用时,不会立即执行,而是暂停待命的状态,因此不会有Start输出。直到其next()调用才执行。

var ret = gen.next();

// Start!

console.log(ret);

// {value: 0, done: false}

上面ret是generator结果. 它有两个属性:

■value, 在generator函数中的yield值,

■done, 这是一个标识表示generator函数是否返回.

继续代码如下:

console.log(gen.next());

// {value: 1, done: false}

console.log(gen.next());

// {value: 2, done: false}

console.log(gen.next());

// {value: undefined, done: true}

generator在同步编程中没有什么玄机,特别适合在异步编程中。

generator有两个特点:

1.能选择跳出一个函数,让外部代码决定什么时候再跳回这个函数继续执行。
2.能够进行异步控制。

看下面异步执行代码:

var gen = generator();

console.log(gen.next().value);

setTimeout(function() {

 console.log(gen.next().value);

 console.log('第一步');

}, 1000);

console.log('第二步');

输出是:

0
第二步
1
第一步

也就是说,不会在setTimeout这里等待计时结束,而是直接继续“第二步”,不会在setTimeout堵塞。

再看另外一段代码:

function* channel () {

 var name = yield 'hello, what is your name?' // [1]

 return 'well hi there ' + name

}

var gen = channel()

console.log(gen.next().value) // hello, what is your name? [2]

console.log(gen.next('billy')) // well hi there billy [3]

在遍历时也可以使用*:

function* iter () {

 for (var i = 0; i < 10; i++) yield i

}

for (var val of iter()) {

 console.log(val) // outputs 1?—?9

}

普遍的误解

既然我可以暂停一个函数执行,那么是不是让它们并行执行呢?不是,因为Javascript是一个单线程,如果你想寻求提升性能,generator并不是你的菜。

比如下面代码分别执行斐波那契数:

function fib (n) {

 var current = 0, next = 1, swap

 for (var i = 0; i < n; i++) {

  swap = current, current = next

  next = swap + next

 }

 return current

}

 

function* fibGen (n) {

 var current = 0, next = 1, swap

 for (var i = 0; i < n; i++) {

  swap = current, current = next

  next = swap + next

  yield current

 }

}

性能结果如下:(越高越好)

results:
regular 1263899
generator 37541

generators闪亮点

Generators 能简化JavaScript中函数的复杂性。

懒赋值

懒赋值虽然可以使用JS的闭包实现,但是使用yield会有很大的简化,通过暂停和恢复,我们能够在我们需要的时候获取数值,比如上面fibGen函数可以在我们需要时拉取新值:

var fibIter = fibGen(20)

var next = fibIter.next()

console.log(next.value)

setTimeout(function () {

 var next = fibIter.next()

 console.log(next.value)

},2000)

当然还使用for循环:依然是懒赋值

for (var n of fibGen(20) {

 console.log(n)

}

无限序列

因为可以懒赋值,那么可能表演一些Haskell招数, 类似infinite sequences. 这里能够yield一个无限序列的数量。

function* fibGen () {

 var current = 0, next = 1, swap

 while (true) {

  swap = current, current = next

  next = swap + next

  yield current

 }

}

我们看看一个斐波那契数流的懒赋值,要求它返回5000以后的第一个斐波那契数:

for (var num of fibGen()) {

 if (num > 5000) break

}

console.log(num) // 6765

异步流程控制

使用generators实现异步流程控制,最常见是各种 promise库包,那么它是如何工作呢?

在Node领域,每个事情都是和回调有关,这是我们的低层次异步功能,我们可以使用generators 建立一个通讯通道,从而使用同步编程的风格编写异步代码。

run(function* () {

 console.log("Starting")

 var file = yield readFile("./async.js") // [1]

 console.log(file.toString())

})

注释1表示程序会在等待async.js返回结果以后再继续。

genify是一个将generators带入平常编程环境的框架,使用如下:

npm install genify 进行安装,代码如下:

var Q = require('q');

var fs = require('fs');

var genify = require('genify');

 

// wrap your object into genify function

var object = genify({

 concatFiles: function * (file1, file2, outFile) {

  file1 = yield Q.nfcall(fs.readFile, file1);

  file2 = yield Q.nfcall(fs.readFile, file2);

  var concated = file1 + file2;

 

  yield Q.nfcall(fs.writeFile, outFile, concated);

 

  return concated;

 }

});

 

// concatFiles是一个generator函数,它使用generator强大能力。

object.concatFiles('./somefile1.txt', './somefile2.txt', './concated.txt').then(function (res) {

 // do something with result

}, function (err) {

 // do something with error

});

以上这篇在Node.js中使用Javascript Generators详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript 写类方式之四
Jul 05 Javascript
jquery实现效果比较好的table选中行颜色
Mar 25 Javascript
jQuery中Ajax的load方法详解
Jan 14 Javascript
Javascript 正则表达式实现为数字添加千位分隔符
Mar 10 Javascript
JavaScript数据类型之基本类型和引用类型的值
Apr 01 Javascript
jQuery密码强度检测插件passwordStrength用法实例分析
Oct 30 Javascript
Bootstrap每天必学之日期控制
Mar 07 Javascript
javascript之IE版本检测超简单方法
Aug 20 Javascript
对js中回调函数的一些看法
Aug 29 Javascript
微信小程序如何使用canvas二维码保存至手机相册
Jul 15 Javascript
微信小程序按钮点击动画效果的实现
Sep 04 Javascript
JavaScript实现复选框全选功能
Apr 11 Javascript
JavaScript编写检测用户所使用的浏览器的代码示例
May 05 #Javascript
JS中dom0级事件和dom2级事件的区别介绍
May 05 #Javascript
整理JavaScript对DOM中各种类型的元素的常用操作
May 05 #Javascript
jQuery Mobile 和 Kendo UI 的比较
May 05 #Javascript
深入理解js promise chain
May 05 #Javascript
详解JavaScript中基于原型prototype的继承特性
May 05 #Javascript
5个最顶级jQuery图表类库插件【jquery插件库】
May 05 #Javascript
You might like
中国站长站 For Dede4.0 采集规则
2007/05/27 PHP
php中var_export与var_dump的区别分析
2010/08/21 PHP
PHP和JavaScrip分别获取关联数组的键值示例代码
2013/09/16 PHP
php使用Jpgraph绘制复杂X-Y坐标图的方法
2015/06/10 PHP
CI(CodeIgniter)框架中URL特殊字符处理与SQL注入隐患分析
2019/02/28 PHP
javascript跟随滚动效果插件代码(javascript Follow Plugin)
2013/08/03 Javascript
无闪烁更新网页内容JS实现
2013/12/19 Javascript
JavaScript让网页出现渐隐渐显背景颜色的方法
2015/04/21 Javascript
JS实现的简单图片切换功能示例【测试可用】
2017/02/14 Javascript
详解nodejs中的process进程
2017/03/19 NodeJs
javascript字体颜色控件的开发 JS实现字体控制
2017/11/27 Javascript
JavaScript求一组数的最小公倍数和最大公约数常用算法详解【面向对象,回归迭代和循环】
2018/05/07 Javascript
JavaScript设计模式之缓存代理模式原理与简单用法示例
2018/08/07 Javascript
layui表单提交到后台自动封装到实体类的方法
2019/09/12 Javascript
vue vant Area组件使用详解
2019/12/09 Javascript
JS hasOwnProperty()方法检测一个属性是否是对象的自有属性的方法
2021/01/29 Javascript
[44:40]2018DOTA2亚洲邀请赛3月30日 小组赛A组Liquid VS OG
2018/03/31 DOTA
[11:33]DAC2018 4.5SOLO赛决赛 MidOne vs Paparazi第二场
2018/04/06 DOTA
python通过正则查找微博@(at)用户的方法
2015/03/13 Python
Django框架下在视图中使用模版的方法
2015/07/16 Python
PyQT实现多窗口切换
2018/04/20 Python
对python的unittest架构公共参数token提取方法详解
2018/12/17 Python
Python打包模块wheel的使用方法与将python包发布到PyPI的方法详解
2020/02/12 Python
django 连接数据库出现1045错误的解决方式
2020/05/14 Python
Python+Opencv身份证号码区域提取及识别实现
2020/08/25 Python
python中实现栈的三种方法
2020/12/19 Python
汤米巴哈马官方网站:Tommy Bahama
2017/05/13 全球购物
Schutz鞋官方网站:Schutz Shoes
2017/12/13 全球购物
产品销售员岗位职责
2013/12/18 职场文书
修理厂厂长岗位职责
2014/01/30 职场文书
中学生励志演讲稿
2014/04/26 职场文书
应聘销售主管的求职信
2014/04/26 职场文书
甲乙双方合作协议书
2014/10/13 职场文书
幼儿园大班教师个人工作总结
2015/02/05 职场文书
浅谈Python3中datetime不同时区转换介绍与踩坑
2021/08/02 Python
vue使用wavesurfer.js解决音频可视化播放问题
2022/04/04 Vue.js