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

ES6 async await #30

Open
ChuChencheng opened this issue Jan 17, 2020 · 1 comment
Open

ES6 async await #30

ChuChencheng opened this issue Jan 17, 2020 · 1 comment

Comments

@ChuChencheng
Copy link
Owner

ChuChencheng commented Jan 17, 2020

概念

ES2017 引入的 async, await 实际上是 Generator 函数的语法糖,使异步操作的写法更加方便。

(既然是语法糖,那我们就可以尝试用 Generator 自己去手写一个 async, await 了 😆 )

跟 Generator 函数比较,可以发现,语法上,就是把 * 号换成 asyncyield 关键字换成 await 而已。但是,肯定不只是替换关键字这么简单,不然为何不用 Generator 。

对 Generator 的改进

  1. 内置执行器,不用像 Generator 函数返回迭代器那种模式那样,手动去执行 next
  2. 更好的语义
  3. async 函数的返回值是 Promise

实现一个 async

假设有以下代码:

function getAsyncValue () {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, 10, 123)
  })
}

async function asyncFunction (p) {
  console.log('param: ', p)
  const value = await getAsyncValue()
  return value
}

asyncFunction(666).then((result) => {
  console.log(result)
})

// param: 666
// 123

如果只依赖 Generatoryield 语法,不使用 async, await ,但要实现同样效果的话,首先把 await 替换成 yield ,然后实现 async 包装:

const _async = (generator) => {
  return function (...args) {
    // async 函数返回一个 Promise
    return new Promise((resolve, reject) => {
      // Promise 内部会自动将 Generator 函数返回的迭代器执行到最后
      const it = generator(...args)
      const step = (nextFunction) => {
        let next
        try {
          next = nextFunction()
        } catch (e) {
          reject(e)
        }
        if (next.done) {
          return resolve(next.value)
        }
        // 其中, next 的执行时机就是 yield 后面的 Promise 状态改变的时候
        // next 的参数就是上一个 yield 的值
        Promise.resolve(next.value).then((value) => {
          return step(() => it.next(value))
        }, (reason) => {
          return step(() => it.throw(reason))
        })
      }
      step(() => it.next())
    })
  }
}

最后就可以改写成非语法糖的 Generator 语法形式:

function getAsyncValue () {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, 10, 123)
  })
}

const asyncFunction = _async(function* (p) {
  console.log('param: ', p)
  const value = yield getAsyncValue()
  return value
})

asyncFunction(666).then((result) => {
  console.log(result)
})

// param: 666
// 123

参考

http://es6.ruanyifeng.com/#docs/async

@ChuChencheng
Copy link
Owner Author

scriptoj 上的题目: #72 使用 generator 模拟 async/await

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

No branches or pull requests

1 participant