JavaScript 中使用异步的情况非常多, 因为 js 采取单线程, 如果某段代码处理时间过长, 后面的代码将一直等待其执行完毕。
由此产生的处理方案是, 任务队列与事件循环(event loop), 无论是最初的回调函数(并非只用在异步), 还是后面解决 callback hell 而出现的 promise 等, 都是依靠在这个机制上的。
主线程遇到异步函数时, 将其扔给异步模块, 继续执行主线程中剩下的部分, 当异步函数满足了执行要求时, 将回调函数放入任务队列中, 主线程完成后, 才会从任务队列中选择任务执行, 而 event loop 负责的是不断从任务队列中取代码, 详细请看 - JavaScript 异步、栈、事件循环、任务队列
历史演变情况
易嵌套的 callback ->
promise ->
包装 promise 的 generator ->
generator 的语法糖 await
promise
基础概念
JS里一个promise可以有以下几种基本状态:
1.nothing happened yet
2."locked in" to another promise
3.fulfilled
4.rejected
其中{1,2}为pending
,{3,4}为settled
,{2,3,4}为resolved
,{1}为unresolved
。详细可以看 Promise的fulfill和resolve
Promise 对象用于表示一个异步操作的最终完成 (或失败), 及其结果值。Promise 的参数 executor 函数在 Promise 构造函数返回所建 Promise 实例对象前被调用, 当异步成功完成并调用 resolve 函数时, 将会将 Promise 的状态 [[PromiseState]]
更改为 fulfilled (chrome 中是 resolved), 如果没有调用 resolve 将一直是 pending 状态
结果值 是 Promise 内置伪属性 internal slots [[PromiseValue]]
(chrome devtool 将它暴露出来了), 它将作为参数传入 之后 then
的参数 onFulfilled 或 onRejected 中
基础使用
下方新构建一个 Promise 的对象, 当执行到 resolve 时, 将 [[PromiseState]]
改为 fulfilled, 当 Promise 变成接受状态(fulfilled)时调用 then
中的 onFulfilled。onFulfilled 有一个参数,即接受的最终结果
1 | var p = new Promise(function(resolve, reject){ |
then
链
每次调用 then
后都会返回一个 promise 对象, 返回的情况由 then
中的回调决定, 描述一些常用的情况
- 返回了一个值, 那么
then
返回的 Promise 将会是 fulfilled 并且将返回的值作为下一个then
的 onFulfilled 的参数 - 返回一个未定状态(pending)的 Promise,那么
then
返回 Promise 的状态也是未定的, 并且状态与该 Promise 保持一致, 并依据该 Promise 中的 resolve 和 reject 来使用下一个then
的两个参数详细情况请看 Promise.prototype.then()
1
2
3
4
5
6
7
8
9
10var p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(123)
}, 1000)
})
p.then(res => {
return '456'
}).then(res => {
console.log(res) //打印 456
})
简单 Promise 实现
当然这都是口头上的执行流程, 现在来写一个看看
结构
1
2
3
4class promise{
constructor(){}
then(){}
}构造函数
!!!! 如果不将 then 中的 onFulfilled 函数使用setTimeout 推迟到下个事件循环再执行, 执行顺序会与原生Promise不同
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24constructor(executor){
//初始状态
this._states = 'pending';
this._internalValue = undefined;
// 添加回调函数队列
this._chain = []
const resolve = (res)=>{
this._states = 'fulfilled';
this._internalValue = res;
//如果此时已经有 then 被调用了
for(var {onFulfilled} of this._chain){
//对象结构赋值, chain 中元素都是对象
setTimeout(() => onFulfilled(res), 0);
}
}
const reject = (err)=>{
this._states = 'rejected';
this._internalValue = err;
for(var {onRejected} of this._chain){
setTimeout(() => onRejected(res), 0);
}
}
executor(resolve, reject);
}then 函数编写
如果已经 settled 那就执行, 否则加入执行队列
1
2
3
4
5
6
7
8
9then(onFulfilled, onRejected) {
if (this._states === 'fulfilled') {
onFulfilled(this._internalValue)
} else if (this._state === 'rejected') {
onRejected(this._internalValue)
} else {
this._chain.push({ onFulfilled, onRejected })
}
}Promise 调用链
then()
应该返回一个新 Promise1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20then(onFulfilled, onRejected) {
var self = this
return new promise((resolve, reject) => {
// 确保在 onFulfilled() 和 onRejected() 的错误将导致返回的 promise 失败(reject)
const _onFulfilled = (res) => {
resolve(onFulfilled(res));
};
const _onRejected = (err) => {
reject(onRejected(err));
};
console.log(self === this) //。。。。
if (this._state === 'fulfilled') {
_onFulfilled(this._internalValue);
} else if (this._state === 'rejected') {
_onRejected(this._internalValue);
} else {
this._chian.push({ onFulfilled: _onFulfilled, onRejected: _onRejected });
}
});
}
onFulfilled()
返回 Promise 的话
1 | const resolve = res => { |
### generator (可能搭在await里) ### await (待写-水平还要再高点, Promise 就够吃力了, 肯定会补的)!!!! 建议写一段代码, 在脑海中运行一遍, debug 也可以, 实在不行纸上写一遍流程(最佳方案), 这玩意调用来调用去, 脑袋都绕晕了, 可以在下方看看测试对比, 输出可以点击网站左下角的 console 按钮看到
参考文章:
Write Your Own Node.js Promise Library from Scratch
- 对应中文版 从零开始写一个 Promise 库
- 实现进阶版 史上最易读懂的 Promise/A+ 完全实现