在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 相关文章推荐
jQuery库与其他JS库冲突的解决办法
Feb 07 Javascript
jQuery选择器源码解读(三):tokenize方法
Mar 31 Javascript
javascript中eval函数用法分析
Apr 25 Javascript
理解Javascript文件动态加载
Jan 29 Javascript
简单理解js的冒泡排序
Dec 19 Javascript
JS仿JQuery选择器功能
Mar 08 Javascript
解决canvas画布使用fillRect()时高度出现双倍效果的问题
Aug 03 Javascript
JavaScript继承与多继承实例分析
May 26 Javascript
JavaScript实现的拼图算法分析
Feb 13 Javascript
vue接入腾讯防水墙代码
May 07 Javascript
vue 指令和过滤器的基本使用(品牌管理案例)
Nov 04 Javascript
微信小程序学习总结(一)项目创建与目录结构分析
Jun 04 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
PHP EOT定界符的使用详解
2008/09/30 PHP
PHP表单验证的3个函数ISSET()、empty()、is_numeric()的使用方法
2011/08/22 PHP
php数组函数序列之array_sum() - 计算数组元素值之和
2011/10/29 PHP
php第一次无法获取cookie问题处理
2014/12/15 PHP
php使用filter_var函数判断邮箱,url,ip格式示例
2019/07/06 PHP
一个对于Array的简单扩展
2006/10/03 Javascript
css把超出的部分显示为省略号的方法兼容火狐
2008/07/23 Javascript
载入jQuery库的最佳方法详细说明及实现代码
2012/12/28 Javascript
本地图片预览(支持IE6/IE7/IE8/Firefox3)经验总结
2013/03/25 Javascript
jquery获取tr中控件值并操作tr实现思路
2013/03/27 Javascript
浅谈关于JavaScript的语言特性分析
2013/04/11 Javascript
JavaScript函数参数使用带参数名的方式赋值传入的方法
2015/03/19 Javascript
原生JS实现旋转木马式图片轮播插件
2016/04/25 Javascript
全面解析Bootstrap中nav、collapse的使用方法
2016/05/22 Javascript
详解利用exif.js解决ios手机上传竖拍照片旋转90度问题
2016/11/04 Javascript
jquery html5 视频播放控制代码
2016/11/06 Javascript
Dropify.js图片宽高自适应的方法
2017/11/27 Javascript
Vue中添加手机验证码组件功能操作方法
2017/12/07 Javascript
vue组件间通信六种方式(总结篇)
2019/05/15 Javascript
vue+elementui实现点击table中的单元格触发事件--弹框
2020/07/18 Javascript
Vant picker 多级联动操作
2020/11/02 Javascript
python2.7实现FTP文件下载功能
2018/04/15 Python
python模拟表单提交登录图书馆
2018/04/27 Python
Python类装饰器实现方法详解
2018/12/21 Python
pandas 把数据写入txt文件每行固定写入一定数量的值方法
2018/12/28 Python
python找出因数与质因数的方法
2019/07/25 Python
Python中使用socks5设置全局代理的方法示例
2020/04/15 Python
html5 canvas合成海报所遇问题及解决方案总结
2017/08/03 HTML / CSS
智利最大的网上商店:Linio智利
2016/11/24 全球购物
高清安全摄像头系统:Lorex Technology
2018/07/20 全球购物
波兰家居饰品和厨房配件网上商店:Maleomi
2020/12/15 全球购物
应届毕业生个人求职自荐信
2014/01/06 职场文书
2014年学习雷锋活动总结
2014/03/01 职场文书
绿里奇迹观后感
2015/06/15 职场文书
爱的教育观后感
2015/06/17 职场文书
《卧薪尝胆》读后感3篇
2019/12/26 职场文书