使用
基本使用
(new Promise(executor))
.then(onFulfilled,onRejected)
// 也可以不指定onRejected,那么使用默认onRejected
(new Promise(executor))
.then(onFulfilled,onRejected)
// 或者不指定onFulfilled,同样的会使用默认onFulfilled
(new Promise(executor))
.catch(onRejected)
默认onFulfilled和onRejected函数大概是这样:
const defaultOnFulfilled = v => v
const defaultOnRejected = error => throw error
then和catch都是返回一个新的promise.
Promise的链式调用
promise.then(),promise.catch() 和 promise.finally()都会新生成的 promise 对象。
const myPromise =
(new Promise(executor))
.then(onFulfilledA,onRejectedA)
.then(onFulfilledB,onRejectedB)
.then(onFulfilledC,onRejectedC);
// 或者,这样可能会更好...
const myPromise =
(new Promise(executor))
.then(onFulfilledA)
.then(onFulfilledB)
.then(onFulfilledC)
.catch(onRejectedAny);
这些函数的返回决定着链式调用中下一个promise的状态是什么,throw导致rejected,其他导致resolved:
onFulfilled(value) { /*...*/; return nextValue; }
onRejection(reason) { /*...*/; throw nextReason; }
onRejection(reason) { /*...*/; return nextValue; }
对于代码:
const promiseA = new Promise(executor);
const promiseB = promiseA.then(onFulfilledB, onRejectedB);
const promiseC = promiseB.then(onFulfilledC, onRejectedC);
const promiseD = promiseB.then(onFulfilledD, onRejecteD);
这些promise们关系如下图所示:
每个promise依赖它的上一个promise, 换个角度,我们也可以认为, 上个promise的输入是下一个promise的输出。
被返回的 nextValue 可能是另一个promise对象,这种情况下这个promise会被动态地插入链式调用。
链式调用中的 promise 们是嵌套起来的,像是一个栈:
(promise D, (promise C, (promise B, (promise A) ) ) )
当存在一个 nextValue 是 promise 时,就会出现一种动态的替换效果。return 会导致一个 promise 被弹出,但这个 nextValue promise 则会被推入被弹出 promise 原来的位置。对于上面所示的嵌套场景,假设与 "promise B" 相关的 .then() 返回了一个值为 "promise X" 的 nextValue 。那么嵌套的结果看起来就会是这样:
(promise D, (promise C, (promise X) ) )
手写 Promise
简易版 Promise
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
class Promise {
constructor(fn) {
this.state = PENDING
this.value = null
this.resolvedCallbacks = []
this.rejectedCallbacks = []
try {
fn(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
resolve(value) {
if (this.state === PENDING) {
this.state = RESOLVED
this.value = value
this.resolvedCallbacks.map(cb => cb(this.value))
}
}
reject(value) {
if (this.state === PENDING) {
this.state = REJECTED
this.value = value
this.rejectedCallbacks.map(cb => cb(this.value))
}
}
then(onFulfilled, onRejected) {
// 默认的onFulfilled和onRejected
const defaultOnFulfilled = v => v
const defaultOnRejected = error => throw error
onFulfilled = onFulfilled || defaultOnFulfilled
onRejected = onRejected || defaultOnRejected
// 如果状态为PENDING, 则加入callbacks
if (this.state === PENDING) {
this.resolvedCallbacks.push(onFulfilled)
this.rejectedCallbacks.push(onRejected)
}
// 否则直接执行
if (this.state === RESOLVED) {
onFulfilled(this.value)
}
if (this.state === REJECTED) {
onRejected(this.value)
}
}
}
then 的链式调用&值穿透特性
我们改写then, 让它返回一个新的promise:
then(onFulfilled, onRejected) {
...
return new Promise((resolve, reject) => {
// 注意: 为了简单,并没有处理resutl为promise的情况
if (this.state === PENDING) {
this.resolvedCallbacks.push(() => {
try {
const result = onFulfilled(this.value)
resolve(result)
} catch (error) {
reject(error)
}
})
this.rejectedCallbacks.push(() => {
try {
const result = onRejected(this.value)
reject(result)
} catch (error) {
reject(error)
}
})
}
if (this.state === RESOLVED) {
try {
const result = onFulfilled(this.value)
resolve(result)
} catch (error) {
reject(error)
}
}
if (this.state === REJECTED) {
try {
const result = onRejected(this.value)
reject(result)
} catch (error) {
reject(error)
}
}
})
}
模拟微任务
onFulfilled和onRejected是异步执行的, 因为我们不能直接添加微任务, 我们只好用setTimeout(fn, 0)
来模拟:
resolve(value) {
setTimeout(() => {
if (this.state === PENDING) {
this.state = RESOLVED
this.value = value
this.resolvedCallbacks.map(cb => cb(this.value))
}
}, 0)
}
reject(value) {
setTimeout(() => {
if (this.state === PENDING) {
this.state = REJECTED
this.value = value
this.rejectedCallbacks.map(cb => cb(this.value))
}
}, 0)
}
then() {
if (this.state === PENDING) { ... }
if (this.state === RESOLVED) {
setTimeout(() => {
try {
const result = onFulfilled(this.value)
resolve(result)
} catch (error) {
reject(error)
}
}, 0)
}
if (this.state === REJECTED) {
setTimeout(() => {
try {
const result = onRejected(this.value)
reject(result)
} catch (error) {
reject(error)
}
}, 0)
}
}
添加微任务时机:
-
当状态由 PENDING 变为 RESOLVED 或 REJECTED 时(调用resolve()或reject()), 将 this.resolvedCallbacks 或 this.rejectedCallbacks 中的函数添加到微任务队列。
-
或者在状态已经为 RESOLVED 或 REJECTED 时,调用then方法,会直接将 onFulfilled 或 onRejected 函数加入到微任务队列。
我们看个例子:
const promise = Promise.resolve(1)
promise.then(val => console.log(val)) // 状态已经为RESOLVED, 执行完这句,函数val => console.log(val) 加入微任务队列,但是要等到本次宏任务执行完成之后再执行
console.log(2)
// 结果: 2, 1
思考题
console.log('1');
setTimeout(() => {
console.log("2")
Promise.resolve().then(() => {
console.log("3")
})
}, 0);
new Promise((resolve, reject) => {
console.log("4")
setTimeout(() => {
console.log("5")
resolve("6");
}, 0);
}).then((res) => {
console.log("7");
setTimeout(() => {
console.log(res)
}, 0);
}).then(() => {
console.log("8");
}).then(() => {
console.log("9");
});
- 第一轮:宏任务1, 4; 微任务:空
- 第二轮:宏任务2; 微任务:3
- 第三轮:宏任务5, 微任务:resolve了,把对应微任务加入~~7、8、9
- 第四轮:6 结果依次输出:1 4 2 3 5 7 8 9 6