有很多,如:
- 1、cb(回调函数,如ajax)
- 2、事件监听
- 3、发布订阅
- 4、Promise等
下面来好好讲讲常用的Promise、async/await这些:
回调函数 -> Promise -> generator/yield -> async/await
async 是Generator函数的语法糖,并对Generator函数进行了改进
async 就是将 Generator 函数和自栋执行器,封装在一个函数中。
async function fn() {
// ...
}
// 等价于
function fn() {
return spawn(function * () { // spawn 是自执行器
// ...
})
}
spawn [spɔːn] n. 卵;菌丝;产物
function spawn(genF){
return new Promise((resolve, reject)=>{
const gen = genF() // 先将Generator函数执行下,拿到遍历器对象
// 声明step
function step(nextF) {
let next
try {
next = nextF()
} catch(e){
return reject(e)
}
if(next.done){
return resolve(next.value)
}
Promise.resolve(next.value).then((v)=>{
step(()=>{return gen.next(v)})
}, (e)=>{
step(()=>{return gen.throw(e)})
})
};
// 自执行
step(()=> {return gen.next(undefinex)})
})
}
关于Generator
Generator 与上下文
Generator 函数, 它执行产生的上下文环境,一旦遇到yield命令,就会暂时退出堆栈,但是并不消失,里面的所有变量和对象会冻结在当前状态。等到对它执行next命令时,这个上下文环境又会重新加入调用栈,冻结的变量和对象恢复执行。
Generator 的实现
具体请参考alloyteam的文章
js 的 Generator
并非由引擎从底层提供额外的支持,而是通过代码的编写,来实现的函数暂停、按序执行。 在实现 Generator
过程中有两个关键点,一是要保存函数的上下文信息,二是实现一个完善的迭代方法,使得多个 yield 表达式按序执行,从而实现生成器的特性。 大体上就是使用由 switch case
组成的状态机模型中, 除此之外,利用闭包技巧,保存生成器函数上下文信息。
Regenerator
通过工具函数将生成器函数包装,为其添加如 next/return
等方法。同时也对返回的生成器对象进行包装,使得对 next
等方法的调用,最终进入由 switch case
组成的 状态机 模型中。除此之外,利用闭包 技巧,保存生成器函数上下文信息。
上述过程与 C#中 yield 关键字的实现原理基本一致,都采用了编译转换思路,运用状态机模型,同时 保存函数上下文信息 ,最终实现了新的 yield 关键字带来的新的语言特性。
网友评论