Generator函数异步应用

知识点简单回顾

在Generator函数语法解析篇的文章中有说到,Generator函数可以定义多个内部状态,同时也是遍历器对象生成函数。yield表达式可以定义多个内部状态,同时还具有暂停函数执行的功能。调用Generator函数的时候,不会立即执行,而是返回遍历器对象。

遍历器对象的原型对象上具有next方法,可以通过next方法恢复函数的执行。每次调用next方法,都会在遇到yield表达式时停下来,再次调用的时候,会在停下的位置继续执行。调用next方法会返回具有value和done属性的对象,value属性表示当前的内部状态,可能的值有yield表达式后面的值、return语句后面的值和undefined;done属性表示遍历是否结束。

yield表达式默认是没有返回值的,或者说,返回值为undefined。因此,想要获得yield表达式的返回值,就需要给next方法传递参数。next方法的参数表示上一个yield表达式的返回值。因此在调用第一个next方法时可以不传递参数(即使传递参数也不会起作用),此时表示启动遍历器对象。所以next方法会比yield表达式的使用要多一次。

更加详细的语法可以参考这篇文章。

异步任务的封装

yield表达式可以暂停函数执行,next方法可以恢复函数执行。这使得Generator函数非常适合将异步任务同步化。接下来会使用setTimeout来模拟异步任务。

const person = sex => {returnnew Promise((resolve, reject) => {    window.setTimeout(() => {      const data = {        sex,name:'keith',        height: 180      }      resolve(data)    }, 1000)  })}function*gen() {const data = yield person('boy')  console.log(data)}const g = gen()const next1 = g.next() // {value: Promise,done:false}next1.value.then(data => {  g.next(data)})

从上面代码可以看出,第一次调用next方法时,启动了遍历器对象,此时返回了包含value和done属性的对象,由于value属性值是promise对象,因此可以使用then方法获取到resolve传递过来的值,再使用带有data参数的next方法给上一个yield表达式传递返回值。

此时在const data = yield person()这句语句中,就可以得到异步任务传递的参数值了,实现了异步任务的同步化。

但是上面的代码会有问题。每次获取异步的值时,都要手动执行以下步骤

const g = gen()const next1 = g.next() {value: Promise,done:false}next1.value.then(data => {  g.next(data)})

上面的代码实质上就是每次都会重复使用value属性值和next方法,所以每次使用Generator实现异步都会涉及到流程控制的问题。每次都手动实现流程控制会显得麻烦,有没有什么办法可以实现自动流程控制呢?实际上是有的: )

thunk函数实现流程控制

thunk函数实际上有些类似于JavaScript函数柯里化,会将某个函数作为参数传递到另一个函数中,然后通过闭包的方式为参数(函数)传递参数进而实现求值。

函数柯里化实现的过程如下

functioncurry (fn) {  const args1 = Array.prototype.slice.call(arguments, 1)returnfunction() {    const args2 = Array.from(arguments)    const arr = args1.concat(args2)returnfn.apply(this, arr)  }}

使用curry函数来举一个例子: )

// 需要柯里化的sum函数const sum = (a, b) => {returna + b}curry(sum, 1)(2)  // 3

而thunk函数简单的实现思路如下:

// ES5实现const thunk = fn => {returnfunction() {    const args = Array.from(arguments)returnfunction(callback) {      args.push(callback)returnfn.apply(this, args)    }  }}// ES6实现const thunk = fn => {returnfunction(...args) {returnfunction(callback) {returnfn.call(this, ...args, callback)    }  }}

从上面thunk函数中,会发现,thunk函数比函数curry化多用了一层闭包来封装函数作用域。

使用上面的thunk函数,可以生成fs.readFile的thunk函数。

const fs = require('fs')constreadFileThunk = thunk(fs.readFile)readFileThunk(fileA)(callback)

使用thunk函数将fs.readFile包装成readFileThunk函数,然后在通过fileA传入文件路径,callback参数则为fs.readFile的回调函数。

omega-shs.fdcpx.net

omega-bjs.fdcpx.net

omega-shenzhen.biaoshouhou.cn

omega-gzs.biaoshouhou.cn

omega-shs.audemarsweixiu.com

omega-bjs.audemarsweixiu.com

omega-shenzhen.hidcwatch.com

omega-gzs.hidcwatch.com

omega-shs.fjfsx.com

omega-bjs.fjfsx.com

omega-shenzhen.hntwx.cn

omega-gzs.hntwx.cn

omega-shs.hx626.com

omega-bjs.hx626.com

omega-shenzhen.watchjwf.cn

omega-gzs.watchjwf.cn

omega-shs.shjshdzb.com

omega-bjs.shjshdzb.com

omega-shenzhen.shmwatch.cn

omega-gzs.shmwatch.cn

omega-shs.gyjshd.com

omega-bjs.gyjshd.com

omega-shenzhen.zhcxb.cn

omega-gzs.zhcxb.cn

omega-shenzhen.jshdvip.com

omega-gzs.jshdvip.com

omega-shs.gyjshdzb.com

omega-bjs.gyjshdzb.com

omega-sys.jhpwd.cn

omega-zzs.jhpwd.cn

omega-shenzhen.wzjshd.com

omega-gzs.wzjshd.com

omega-shs.jsfltime.com

omega-bjs.jsfltime.com

omega-sys.watchwb.cn

omega-css.watchwb.cn

omega-shenzhen.watch-hdl.com

omega-gzs.watch-hdl.com

omega-shs.watchhdlb.cn

omega-bjs.watchhdlb.cn

omega-whs.watchhdli.cn

omega-nbs.watchhdli.cn

omega-shenzhen.watchrhf.cn

omega-gzs.watchrhf.cn

omega-shs.watchec.cn

omega-bjs.watchec.cn

omega-whs.watchda.cn

omega-xms.watchda.cn

omega-hzs.csjshd.com

omega-njs.csjshd.com

当然,还有一个thunk函数的升级版本thunkify函数,可以使得回调函数只执行一次。原理和上面的thunk函数非常像,只不过多了一个flag参数用于限制回调函数的执行次数。下面我对thunkify函数做了一些修改。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容