前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《你不知道的JavaScript》:生成器函数执行模式初体会

《你不知道的JavaScript》:生成器函数执行模式初体会

作者头像
前端_AWhile
发布2019-08-29 11:14:46
3570
发布2019-08-29 11:14:46
举报
文章被收录于专栏:前端一会前端一会

在js中,有一个普遍依赖的假定:一个函数一旦开始执行,就会运行到结束,期间不会有其他代码能够打断它并插入其间。

但ES6中引入了一个新的函数类型,它并不符合这种运行到结束的特性。这类新的函数被称为生成器。

看下面的普通函数示例:

代码语言:javascript
复制
var x = 1;function foo(){
   x++;
   bar();
   console.log(x);
}

function bar(){
   x++;
}

foo();      // 3

上例中,bar()会在foo()函数中执行,导致foo()函数执行后x值为3。但如果bar()不在foo函数中,最后的显示结果就是2,而不是3。

那可以想个问题,如果bar()不在那儿,但出于某种原因要它仍然可以在x++console.log(x);语句之间运行,该怎么实现呢?

此时就可以使用ES6的生成器来实现这样的功能:

代码语言:javascript
复制
var x = 1;function *foo(){
   x++;
   yield;
   console.log(x);
}

function bar(){
   x++;
}

// 构造一个迭代器it来控制生成器*foo()
var it = foo();
//这里启动  *foo()生成器
it.next();console.log(x);     // 2
bar();
console.log(x);     // 3
it.next();

首先注意上例中的生成器格式 function *foo(){},通常这个*号位置还有其他两种,它们都是等价的:function* foo(){}function*foo(){}。而这里采用第一种格式是因为使用*foo(){}来引用生成器时会比较一致,如果只是foo()的形式,就不容易搞清指的是生成器还是常规函数。所以这只是一种风格偏好。

现在在描述下上例的运行过程:

  • var it = foo();运算并没有执行生成器 *foo(),而只是构造了一个迭代器(iterator),这个迭代器会控制它的执行。
  • 第一个it.next();启动了生成器*foo(),并运行了*foo()第一行的代码x++
  • *foo()yield语句处暂停,在这个点位上第一个it.next()调用结束。此时*foo()仍然是运行且活跃的,但函数处理暂停状态。
  • 此时查看x的值,是2
  • 然后调用bar(),它通过x++两次递增x的值
  • 此时再次查看x的值,它变成了3
  • 最后的it.next()调用从暂停处恢复了生成器*foo()的执行,并运行console.log()语句,这条语句使用当前x的值3。

所以可以这样理解:foo()启动了,但是没有完整运行,它在yield处暂停了。暂停其间可以执行其他需要的代码,执行完后再调用迭代器it的next()方法恢复生成器foo()并让它继续执行到结束。

所以生成器就是一类特殊的函数,可以一次或多次启动和停止,并不一定非得到完成。

它将用于构建以生成器作为异步流程控制的代码模式的基础构件之一。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-01-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端小二 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档