Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

async await 和 generator #65

Open
wuyanqian0503 opened this issue Jul 16, 2021 · 1 comment
Open

async await 和 generator #65

wuyanqian0503 opened this issue Jul 16, 2021 · 1 comment

Comments

@wuyanqian0503
Copy link
Owner

wuyanqian0503 commented Jul 16, 2021

Generator

Generator对象是由 Generator Function 返回的,并且它符合可迭代协议和迭代器协议。

Generator Function的语法如下:

function* gen() {
  yield 1;
  yield 2;
  yield 3;
}

let g = gen();
// "Generator { }"

通过在function关键字后添加星号来表示这是一个 Generator 函数,那么这个函数的返回值就会是一个 Generator 对象,我们可以对这个对象进行迭代。

Generator.prototype.next()

返回一个由yeild生成的值。

generator function被执行时,会生成一个generator实例,函数体内的语句并不会立即执行,而是等到调用generator的next方法时,执行到下一个yeild后将程序控制权交出去,等待下一次generator对象再次调用next方法再将程序控制权拿回来,并且把next方法的入参作为上一个yeild语句的值。

当语句中的所有yeild都执行完毕后,next方法将返回一个包含done为true的对象,并且value为函数的返回值。

Generator.prototype.return()

返回给定的值并结束生成器。

Generator.prototype.throw()

向生成器抛出一个错误。

可以被try catch捕获到异常。

@wuyanqian0503
Copy link
Owner Author

实现 async await

我们知道,asycn await 其实是将一个函数包装成一个Promise,这个promise在创建时立即执行了这个函数,并且在遇到函数中的await时,会等待await右侧表达式完全resolve后,在继续执行下面的语句,并且将函数的返回值作为这个Promise的resolve的值。

那么我们其实就可以利用Gnerator的流程控制的原理,来实现await的工作。

首先我们可以利用yeild来替代await,但是是await右侧resolve以后,会自动执行后续语句,yeild则需要调用gen的next方法才可以。

所以我们需要利用Promise.resolve.then方法来处理await右侧的值,在其resolve以后去调用next。

不过前提是我们要先拿到gen。

function getData() {
  console.log('getData')
  return '11111111'
}

// 假设编译器可以将async方法编译成generator function,其中await也会被编译成yeild
function* testG() {
  const data = yield getData()
  console.log('data: ', data);
  const data2 = yield getData()
  console.log('data2: ', data2);
  return 'success'
}

// 实现

function asyncToGenerator(genertatedFunc) {
  return function asyncFunc() {
    return new Promise((resolve, reject) => {
      const gen = genertatedFunc()
      const step = (funcName, param) => {
        let generatorResult
        try {
          generatorResult = gen[funcName](param)
        } catch (err) {
          reject(err)
        }
        
        const { value, done } = generatorResult
        if (done) {
          resolve(value)
        } else {
          new Promise((resolve) => resolve(value))
            .then((res) => {
              step("next", res)
            })
            .catch((err) => {
              step("throw", err)
            })
        }
      }
      step()
    })
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant