虽然Promise
解决了callback hell
的问题,但遇到复杂业务的时候可能会充斥着大量的 then
函数。
故 es7 引入了async/await
, 这个被称作终极的异步解决方案,其实是Generator
的语法糖
Generator
Generator
函数是一个状态机,封装了多个内部状态。执行 Generator
函数会返回一个迭代器对象,可以依次遍历 Generator
函数内部的每一个状态。但只有调用next
方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield
表达式就是暂停标志。
function* helloWorldGenerator() {
yield 'hello'
yield 'world'
return 'ending'
}
var hw = helloWorldGenerator()
hw.next() // { value: 'hello', done: false }
hw.next() // { value: 'world', done: false }
hw.next() // { value: 'ending', done: true }
hw.next() // { value: undefined, done: true }
Generator
函数被调用时并不会执行,只有当调用next
方法、内部指针指向该语句时才会执行,即函数可以暂停,也可以恢复执行。每次调用遍历器对象的next
方法,就会返回一个有着 value
和done
两个属性的对象。value
属性表示当前的内部状态的值,是yield
表达式后面那个表达式的值;done
属性是一个布 尔值,表示是否遍历结束。
Generator 函数暂停恢复执行原理
一个线程(或函数)执行到一半,可以暂停执行,将执行权交给另一个线程(或函数),等到稍后收回执行权的时候,再恢复执行。这种可以并行执行、交换执行权的线程(或函数),就称为协程。
协程是一种比线程更加轻量级的存在。普通线程是抢先式的,会争夺 cpu 资源,而协程是合作的,可以把协程看成是跑在线程上的任务,一个线程上可以存在多个协程,但是在线程上同时只能执行一个协程。它的运行流程大致如下:
- 协程 A 开始执行
- 协程 A 执行到某个阶段,进入暂停,执行权转移到协程 B
- 协程 B 执行完成或暂停,将执行权交还 A
- 协程 A 恢复执行
执行器
通常,我们把执行生成器的代码封装成一个函数,并把这个执行生成器代码的函数称为执行器, co
模块就是一个著名的执行器
Generator
是一个异步操作的容器。它的自动执行需要一种机制,当异步操作有了结果,能够自动交回执行权。两种方法可以做到这一点:
- 回调函数。将异步操作包装成
thunk
函数,在回调函数里面交回执行权。 Promise
对象。将异步操作包装成Promise
对象,用then