5. async、await 实现原理

150 阅读2分钟

JavaScript 异步编程回顾

由于 JavaScript 是单线程执行模型,因此必须支持异步编程才能提高运行效率。异步编程的语法目标是让异步过程写起来像同步过程。

1. 回调函数

回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务的时候,就直接调用这个函数

image.png

回调函数最大的问题是容易形成回调地狱,即多个回调函数嵌套,降低代码可读性,增加逻辑的复杂性,容易出错。

image.png

2. Promise

为解决回调函数的不足,社区创造出 Promise。

image.png Promise 实际上是利用编程技巧将回调函数的横向加载,改成纵向加载,达到链式调用的效果,避免回调地狱。最大问题是代码冗余,原来的任务被 Promise 包装了一下,不管什么操作,一眼看去都是一堆 then,原来的语义变得很不清楚。

3. async、await

为了解决 Promise 的问题,async、await 在 ES7 中被提了出来,是目前为止最好的解决方案

image.png async、await 函数写起来跟同步函数一样,条件是需要接收 Promise 或原始类型的值。是最容易理解的形式。

async、await 原理

1. generator

generator是‘多个线程协助方式完成异步任务’在ES6中的实现。

image.png 整个 generator 函数就是一个封装的异步任务,异步操作需要暂停的地方,都用 yield 语句注明。generator 函数的执行方法如下:

function* gen(x) {
    console.log('start')
    const y = yield x * 2
    return y
}
const g = gen(1)
g.next() // start {value: 2; done: false}
g.next(4) // {value: 4; done: true}

gen() 不会立即执行,而是一上来就暂停,返回一个 Iterator 对象(具体可以参考 Iterator遍历器 )

  • 每次 g.next() 都会打破暂停状态去执行,直到遇到下一个 yield 或者 return
  • 遇到 yield 时,会执行 yield 后面的表达式,并返回执行之后的值,然后再次进入暂停状态,此时 done: false 。
  • next 函数可以接受参数,作为上个阶段异步任务的返回结果,被函数体内的变量接收
  • 遇到 return 时,会返回值,执行结束,即 done: true
  • 每次 g.next() 的返回值永远都是 {value: ... , done: ...} 的形式

async/await 怎么进行错误处理?

一般情况下 async/await 在错误处理方面,主要使用 try/catch,像这样

image.png 多个异步操作,如果都充斥着 try/catch很不优雅,既然是 promise 那么就可以使用 then 函数。 image.png

2.generator自执行器

3. thunk函数

4. CO函数库