key: Generator函数是ES6提供的一种异步编程解决方案

Generator函数和普通函数就有两个区别:

一是  function命令与函数名之间有一个星号 *

二是 函数体内有yield语句 定义不同的内部状态

----------------------------------------------------------------------------------

Generator函数返回的是一个遍历器对象。

为什么,请看下面的代码:

var g = gen()

g[Symbol.iterator] () ===g

MDN-Symbol.iterator   and  Ruanyf-ES6-Guide Iterator

----------------------------------------------------------------------------------

我们从一个例子开始:

function * gen () {console.log('started')console.log(yield 1)yield 2yield 3
}

可以这样理解yield只是一个暂停状态的标记。

我们先获取这个遍历对象,var g = gen()

g.next()第一次函数开始执行,遇到yield所在的行就停止了,所以这一次是输出了一个'started'. 但是我们知道.next()返回一个对象,对象的value 就是第一个暂停标记的yiled 后面表达式的值。 这一步的g.next()应该是{ value: 1, done: false }

g.next()第二次执行,我们传递一个参数,g.next('abc') ,这时候我们先不讨论参数,只是讨论暂停状态的标记是yield 2, 这时候执行的代码是 console.log(yield 1), 但是这里我们传递了一个参数, 这个参数是上一个暂停标记(yield 表达式,请注意是整个yield表达式,也就是yield+expression)的值。所以这个yield 1 最后的值是'abc', 这时候输出的是一个 'abc'。 这里其实有点绕,实际上就是next(value),  这个value是上一个暂停表达式的值。

----------------------------------------------------------------------------------

前面我们说了Generator是ES6的一个异步解决方案,但是我们看了前面的例子,都是以同步的语法和书序来执行完。到底generator是怎么帮助我们来处理异步方法呢?

没错,就是通过next(),next()方法可以传递一个参数,这个参数就是上一个yield 表达式的值。

function *gen (a) {var x = yield a + 1var y = yield x * 2return y
}

var g = gen(3)

我们运行几次的结果是这样的:

g.next()  // {value: 4, done: false}

g.next() // {value: NaN, done: false}  这一步因为我们没有给上一个 (yield 表达式)赋值,如果我们这样写,g.next(5),这样上一个 yield a+1 的值就是 5,x的值就为5, 这一步.next()的value就是5*2为0。 但是这个参数我们是不能写死的,因为这样没有任何的实际意义。我们可以将上一次的next()的value给保存下来,然后作为参数传递给下个next()。

我们来写一个简要的流程控制器,专门处理这一串流程:

function exceuteGen(generatorFunc) {

let g = generatorFunc

let value

while(true) {

var temp = g.next(value)

if (!temp.done) {

value = temp.value

} else {

return value

break

}

}

}

var g = gen(3)

console.log('最后的结果是 ' + exceuteGen(g))

function exceuteGen(generatorFunc) {let g = generatorFunclet valuewhile(true) {var temp = g.next(value)if (!temp.done) {value = temp.value} else {return valuebreak}}
}var g = gen(3)
console.log('最后的结果是 ' + exceuteGen(g))

我们来看gen, 里面y是依赖x的,我们以同步的方式去书写这两段代码,最后用一个执行器就完成了异步操作,如果不去写执行器,是不是觉得这样写比callback 和 promise都好的多,个人觉得是的。 callback一堆回调,promise一堆then的情况都比较繁琐,用generator要简洁的多【但是好多场景是generator 和 promise搭配一起使用】。

----------------------------------------------------------------------------------

上面我们举得例子是串行,但是有的情况是需要并行的,比如我们要处理一个汇总数据,需要得到学生数据 和 书籍数据,两个对应方法是 getStudents() 和 getBooks()。 同时去获取这两个数据,然后基于这两个数据去执行下一步骤,我们可以这样写:

function* parallelTask () {let [students, books] = yield [getStudents(),getBooks()]console.log(students, books)
}

//执行器的第二个next传递的参数格式请注意,要可迭代。传入数组或者Set【map请你自己去尝试】,不然会报错:(intermediate value) is not iterable

----------------------------------------------------------------------------------

用Generator处理异步的好处是什么,通过上面的例子我们也能够看出来,是以看起来同步的方式去书写代码,然后用一个执行器去隐藏了异步的一些数据传递。这样我们以更加自然的方式去书写我们的代码。

一般我们都会用一些库比如co,它们帮助我们写好了执行器,我们只需要定义这个generator函数即可。

co模块返回一个promise对象。

查看co的源码,其实可以发现,原理和我们上面写的generator函数执行器是一样的,我理解就是递归(可能不准确),不过co模块做了其他的优化。

递归实现执行器的基本因素是什么?就是每一次传递的参数个数是一样的,我们默认回调里面传给下一个回调的参数是一个[next()的参数默认一个]这样我们写执行器的时候,就直接传递了,但是如果我们的回调参数不只一个,多个嵌套回调,甚至回调参数个数不是规律递增递减,这样的逻辑我们根本不能写一个自动执行器。所以co模块将传入的参数默认转换成promise对象,promise的fullfilled callback function只能接受一个参数,我想这就是为co模块编写自动执行器的一个前提条件

----------------------------------------------------------------------------------

async 和 generator类似,是为了异步操作变得更加简单,

var asyncReadFile = async function() {var f1 = await readFile('/etc/fstab')var f2 = await readFile('/etc/shells')console.log(f1.toString())console.log(f2.toString())
}

和generator比起来好处在于,async函数内置了执行器,我们不用像generator一样,额外的要附加一个执行器, async函数返回的是一个promise对象。

----分割---

我们来给普通对象实现for..of 操作,就是给普通对象增加一个Symbol.iterator属性,这个属性返回一个迭代器对象,看下面:

     var o = {name: "kevin"}o[Symbol.iterator] = function() {var v = 0;return {next: function() {return { value: v++, done: v > 10  }}}}for(let oItem of o) {console.log(oItem)}console.log("\n-----\n")var x = {name: "kevin"}x[Symbol.iterator] = function * () {for(let i = 0; i< Infinity; i += 1) {if(i > 10) break;yield i;}}for(let xItem of x) {console.log(xItem)}

参考资料: generator -ruanyf

https://davidwalsh.name/es6-generators

co -source code

转载于:https://www.cnblogs.com/dongguapifly/p/10627099.html

【javascipt】Generator函数(生成器)相关推荐

  1. JavaScript 异步编程--Generator函数、async、await

    JavaScript 异步编程–Generator函数 Generator(生成器)是ES6标准引入的新的数据类型,其最大的特点就是可以交出函数的执行的控制权,即:通过yield关键字标明需要暂停的语 ...

  2. Generator函数的语法以及异步的应用

    基本概念 Generator函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同.Generator函数有多种理解角度.语法上,首先可以把它理解成,Generator函数是一个状态机,封 ...

  3. es6 中的generator函数控制流程

    Generator函数跟普通函数的写法有非常大的区别: 一是,function关键字与函数名之间有一个星号: 二是,函数体内部使用yield语句,定义不同的内部状态(yield在英语里的意思就是&qu ...

  4. python之路day14--列表生成式、生成器generator、生成器并行

    列表生成式 列表生成式阅读量: 44 现在有个需求,现有列表a=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],要求你把列表里的每个值加1,你怎么实现?你可能会想到2种方式 二逼青年版 ...

  5. python----yield(generator)生成器

    在python编程中 很多时候都需要用到函数 函数可以产生值并通过return返回 但是后时候函数里面产出的值不只有一个 例如: 情景一: def show_num():for n in " ...

  6. lambda 函数与 Generator 函数

    lambda 函数 语法格式: func = lambda 变量1,变量2...:表达式 #赋值 func() #调用 例子: sum = lambda a,b:a+b print(sum(4+7)) ...

  7. “睡服”面试官系列第十八篇之generator函数的语法(建议收藏学习)

    目录 1简介 1.1基本概念 1.2yield 表达式 1.3与 Iterator 接口的关系 2. next 方法的参数 3. for...of 循环 4. Generator.prototype. ...

  8. 第十五节:有一种特殊的函数叫:Generator函数

    今天我们来学习ES6给我们带来的一种新函数,在学习它之前,前端君希望你已经阅读并初步了解了上一节的内容:iterator遍历器.因为本节的内容,是建立在iterator遍历器知识的基础上. 如果是新来 ...

  9. es6 Generator函数概述

    概述 什么是Generator函数 Generator函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同.本章详细介绍 Generator函数的语法和 API,它的异步编程应用请看 ...

最新文章

  1. 态势“知”多少,点开就知道
  2. 记录:C#编程中的字符串
  3. 表单元素聚焦状态回车提交表单问题小记
  4. Pandas数据类型及操作
  5. Oracle案例:一次非常艰难的drop多个PDB的恢复
  6. 深度为你解答怎么避免域名被微信拦截,微信域名防封需要注意哪些问题?
  7. 计算机与管理科学的交叉与融合,计算机信息管理学科交叉融合研究论文
  8. Tomcat----windows系统通过命令符“强制关闭Tomcat”
  9. [原创]Jenkins持续集成工具介绍
  10. 20220103_数据库过程:异常业务量情况通报
  11. 工程制图与计算机绘图教学视频,工程制图与计算机绘图(西电版)第1章_制图的基本知识教材教学课件.ppt...
  12. vue 图片拖拉转放大缩小组件
  13. 计算机操作系统知识点总结(有这一篇就够了!!!)
  14. 摄像头远程监控精灵 4.65
  15. Latex——论文翻译
  16. 【纯干货】SpringBoot 整合 ES 进行各种高级查询搜索
  17. 红黑树详解及其模板类实现
  18. 两层全连接网络反向传播梯度推导(矩阵形式、sigmoid、最小均方差MSE)
  19. 火影忍者379话最新情报
  20. sip协议之网络传输方式

热门文章

  1. python 序列列表区别_Python6序列和列表
  2. busybox linux内核,使用busybox创建精简linux内核实例
  3. php快速排序分割两部分,php四大算法|冒泡排序|快速排序|二分查找
  4. xcode11 新功能_Xcode 11功能
  5. mongodb排序_MongoDB排序
  6. Java 11:字符串类中的新方法
  7. Android拖放– DragLinearLayout
  8. Sobel边缘检测算法及OpenCV函数实现
  9. 新年新气象[xgluxv]
  10. Linux基础命令---检查密码文件pwck 1