阅读 139

Generator函数同步执行异步操作详解

下面代码,首先声明一个 generator 函数 gen,目的是让第一个 yield 语句返回 Promise 的结果,再同步打印结果。

function* gen() {   console.log('starting')   const result = yield asyncFn().then(value => {     g.next(value)   })   console.log('end:', result) // 1s后打印 end: promise value } const g = gen(); function asyncFn() {   return new Promise((resolve) => {     setTimeout(() => {       resolve('promise value')     }, 1000)   }) } const res = g.next() console.log(res) 复制代码

问题一:result 如何同步接收 Promise 结果?

这个问题其实是 yield 语句返回值的问题。先看一段简单的代码。

function* gen() {     console.log('start')     const result = yield 1     console.log(result) } const g = gen() console.log(g.next()) // {value: 1, done: false} console.log(g.next()) // {value: undefined, done: true} 复制代码

gen() 返回的是一个迭代器对象,表示 gen 函数的代码并不会立即执行,而是在调用 next() 方法后开始执行。 所以,我们可以看到在调用 g.next() 方法后,先打印 start,此时 g.next() 的返回值是 {value: 1, done: false},所以 yield 语句后面的值并不是 const result = yield 1 result 的值,而是迭代器 next() 方法的返回值。而 yield 语句则会暂停后面语句的执行。 最后,第二次调用 g.next() 方法,执行剩余的语句,返回 {value: undefined, done: true}, value 是 return 语句返回值,由于此时没有声明 return 语句,所以默认值是 undefined。 done 表示 generator 函数执行结束。

再看一段关于 next() 方法参数的代码

function* gen() {     console.log('start')     const result = yield 1     console.log(result) // do } const g = gen() console.log(g.next()) // 开始执行 console.log(g.next('do')) 复制代码

由上面代码看出,第二个 next 放的参数是第一个 yield 语句的返回值,这是由于第一个 next 方法表示开始执行,而第二个 next 方法才继续执行第一个 yield 后的语句。

所以回到最开始的代码,result 其实是通过 next 方法接收 Promise 执行结果。

const result = yield asyncFn().then(value => {   g.next(value) }) 复制代码

待 asyncFn 方法变成 resolve 状态,使用 then 接受 value,通过 g.next(value) 继续执行 gen 函数。如此,Generator 把异步操作变成了同步执行。

问题二:为什么 gen 函数中可以访问实例 g 调用 g.next()

首先我们看看 js 构造函数的调用

p 引用错误

function P() {     console.log(p) } const p = new P() console.log(p) // Uncaught ReferenceError: Cannot access 'p' before initialization 复制代码

所以,在正常的函数中这种调用方式是不能正常执行的,但是 generator 函数,其实返回的是一个迭代器对象,const g = gen() 这个语句并不会立即执行函数, 而是第一个 g.next() 方法执行后,才开始执行 gen 函数,所以当函数执行时,g 对象其实已经被创建,所以 generator 函数执行时总是可以获取实例 g 也就是迭代器对象的内存。

通过 chrome 浏览器调试可以看到作用域中存在 g 对象 在这里插入图片描述


作者:熊猫的胸毛叫熊毛
链接:https://juejin.cn/post/7034807403904237599


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐