# 10 分钟回顾一下 Promise 和 async/await
- 这里我们不对基础概念有过多的介绍,开始之前,如果对
eventLoop
还不太熟悉的同学可以回顾一下之前的文章Event Loop
# 基于观察者模式实现一个简易版本的 Promise
- 目前我们先不考虑完美的 Promise 的
padding
、fulfilled
、rejected
三种状态,以及finally
、all
、race
、allSettled
等方法和异常情况的处理,用 12 行代码实现不完整的 Promise 异步链式调用,了解 Promise 的设计思路
function MiniPromise(fn) {
var callbacks = [];
function resolve(value) {
callbacks.forEach((callback) => {
//循环通知观察者
callback(value);
});
callbacks = [];
}
this.then = function (cb) {
callbacks.push(cb);
};
fn(resolve);
}
- 我们拿着上面的构造函数来试验一下
new MiniPromise((resolve) => {
console.log('start');
setTimeout(() => {
console.log('success');
resolve('ok');
}, 2000);
}).then((res) => {
console.log(666);
console.log(res);
});
// success
// 666
// ok
# 分析
- 其核心就是一个依赖收集,等待实例的异步函数被调用后,再把我们的依赖一个个依次执行
- 但是完整的 Promise 还是比这个复杂很多,有兴趣的小伙伴可以对着Promises/A+ (opens new window)继续实现下去
# 更优雅的 async/await
- 虽然链式调用解决了回调地狱,但是总体的可读性还是不佳,而解决异步调用的终极方案,就是 ES7 提出的
async/await
函数 async/await
实际上糖是Generator
(生成器)函数的语法糖,对Generator
函数改进并封装- 在
Generator
函数中可以通过yield
关键字,把函数的执行流挂起,再手动调用next()
切换到下一个状态(移动内部指针),在next()
中还可以通过传参使让yield
具有返回值,从而实现改变执行流程
- 在
function* miniAsync(a) {
// await被编译成了yield
const template = yield a + 1;
console.log('data: ', template);
return 'end';
}
const res = miniAsync(1);
res.next(1); // { value: 2, done: false }
res.next(); // { value: underfind, done: true }
- 调用一次 Generator 会在 yield 所在位置停下并执行当行后返回一个包含 value、done 两个键值对的 Object,直到下一次调用或最后代码执行完毕再返回一个 done 为 true 的对象
- 相比于
async/await
,Generator
需要手动调用,而且返回的是 Object 对象不是 Promise 对象,并且await
能够接收异步返回值
# 原理
async/await
实际上是 Generator 结合自执行函数(spawn)
async function fn(args) {
// ...
}
// 等同于
function fn(args) {
return spawn(function* () {
// ...
});
}