ES7 在语法层面上支持了 async/await
关键字,我们将在代码层面上模拟实现 async/await
来理解它的工作原理。
本文旨在说明其工作原理,你应该具备以下前置知识:
- 熟悉
Promise
的概念及使用 - 熟悉
async/await
的概念及使用 - 了解
Generator
的概念
Generator 基础复习
首先复习一下 Js Generator 的基本用法:
1 | function * work() { |
我们调用 work()
这个函数时它返回的是一个 Generator 对象 gen
;
然后我们调用 gen.next()
返回值是 { value: 'hi', done: false }
, 其中 value
字段就是 yield
关键字返回给我们的数据,done
字段表示该 Generator 函数当前并没有执行结束,并且暂停在了 yield
所在的这一行。
当我们第二次调用 gen.next('ha')
的时候,Generator 函数继续执行,并将我们传给 next() 函数的参数值 'ha'
返回并赋值给变量 r
,然后继续运行并打印出 r
,直到遇到 return
语句,函数返回 { value: undefined', done: true }
给我们。
其中 value 是返回值, done 表示 Generator 函数已执行结束并返回。
Generator 函数的一个特点是可以使用 yeild 关键字暂停当前函数的执行,并向调用者返回相应数据以及自己的运行状态( 代码中的
done
字段)。
另外一个特点是,调用者通过next()
函数恢复 Generator 执行时可以通过参数传数据给 Generator 作为 yield 的返回值 (赋给代码中的变量r
)。
run()
有了前面关于 Generator 知识的复习,我们实现本文的核心函数;
它接收一个 Generator 函数 fn
作为参数,它的功能就是模拟 async/await
机制运行该 fn
函数。
1 | function run(fn) { |
在解释我们这个 run()
函数之前,先看一下它的用法示例:
1 | function sleep(duration) { |
看了这个示例代码,应该就能明白 run()
的作用了,实际上通过这个函数,我们已经模拟实现了 async/await
机制;
我们做个不严谨的类比来说明:
function * work() { }
中间的 * 号就相当于async
关键字的作用;yield
关键字就相当于await
关键字;
总结
实际上 async/await
关键字也可以认为是 ES7 的语法糖,我们已经通过 run()
函数来模拟了其工作原理,至于 Js 引擎具体怎么实现的,未来我们写 分析 v8 引擎实现相关文章的时候再细究。