# 手写 Promise
# 构造函数
核心步骤:
定义类 => 添加构造函数 => 定义resolve/reject => 执行回调函数
class MyPromise { | |
// state = PENDING; | |
// result = undefined; | |
constructor(executor) { | |
const resolve = (value) => { | |
} | |
const reject = (reason) => { | |
} | |
executor(resolve, reject); | |
} | |
} |
# 状态及原因
核心步骤:
添加状态 => 添加原因 => 调整resolve/reject => 状态不可逆
const PENDING = 'pending' | |
const FULFILLED = 'fulfilled' | |
const REJECTED = 'rejected'; | |
class MyPromise { | |
state = PENDING; | |
result = undefined; | |
constructor(executor) { | |
// 改状态: pending -> fulfilled | |
const resolve = (value) => { | |
if(this.state === PENDING) { | |
this.state = FULFILLED; | |
this.result = value; | |
} | |
} | |
// 改状态: pending -> rejected | |
const reject = (reason) => { | |
if(this.state === PENDING) { | |
this.state = REJECTED; | |
this.result = reason; | |
} | |
} | |
executor(resolve, reject); | |
} | |
} | |
const p = new MyPromise((resolve, reject) => { | |
resolve('success'); | |
}); | |
console.log(p); |
# then 方法
# 成功或失败回调
根据当前的状态,执行对应的回调函数。特殊的如果传入的回调函数不是函数,返回原值
核心步骤:
添加实例方法 => 参数判断 => 执行成功/失败回调
const PENDING = 'pending' | |
const FULFILLED = 'fulfilled' | |
const REJECTED = 'rejected'; | |
class MyPromise { | |
state = PENDING; | |
result = undefined; | |
constructor(executor) { | |
// 改状态: pending -> fulfilled | |
const resolve = (value) => { | |
if(this.state === PENDING) { | |
this.state = FULFILLED; | |
this.result = value; | |
} | |
} | |
// 改状态: pending -> rejected | |
const reject = (reason) => { | |
if(this.state === PENDING) { | |
this.state = REJECTED; | |
this.result = reason; | |
} | |
} | |
executor(resolve, reject); | |
} | |
then(onFulfilled, onRejected) { | |
// 如果 then 传入的参数不是函数,参考 MDN 文档返回 | |
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value; | |
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }; | |
if(this.state === FULFILLED) { | |
onFulfilled(this.result); | |
} else if(this.state === REJECTED) { | |
onRejected(this.result); | |
} | |
} | |
} | |
const p = new MyPromise((resolve, reject) => { | |
resolve('success'); | |
}); | |
p.then(res => { | |
console.log(res); | |
}, err => { | |
console.log(err); | |
}) | |
console.log(p); |
# 异步和多次调用
根据当前的状态,如果是 pending,先将回调函数保存起来,等状态改变后,再执行回调函数。如果多次调用 then,将回调函数保存起来,等状态改变后,再执行回调函数。
核心步骤:
定义实例属性 => 保存回调函数 => 执行成功/失败回调
const PENDING = 'pending' | |
const FULFILLED = 'fulfilled' | |
const REJECTED = 'rejected'; | |
class MyPromise { | |
state = PENDING; | |
result = undefined; | |
#handlers = []; // [{onFulfilled, onRejected}, 。。。] | |
constructor(executor) { | |
// 改状态: pending -> fulfilled | |
const resolve = (value) => { | |
if(this.state === PENDING) { | |
this.state = FULFILLED; | |
this.result = value; | |
// 执行回调 | |
this.#handlers.forEach(({onFulfilled}) => { | |
onFulfilled(this.result); | |
}) | |
} | |
} | |
// 改状态: pending -> rejected | |
const reject = (reason) => { | |
if(this.state === PENDING) { | |
this.state = REJECTED; | |
this.result = reason; | |
// 执行回调 | |
this.#handlers.forEach(({onRejected}) => { | |
onRejected(this.result); | |
}) | |
} | |
} | |
executor(resolve, reject); | |
} | |
then(onFulfilled, onRejected) { | |
// 如果 then 传入的参数不是函数,参考 MDN 文档返回 | |
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value; | |
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }; | |
if(this.state === FULFILLED) { | |
onFulfilled(this.result); | |
} else if(this.state === REJECTED) { | |
onRejected(this.result); | |
} else if(this.state === PENDING) { | |
this.#handlers.push({ | |
onFulfilled, | |
onRejected | |
}) | |
} | |
} | |
} | |
const p = new MyPromise((resolve, reject) => { | |
setTimeout(() => { | |
resolve('success'); | |
}, 1000); | |
}); | |
p.then(res => { | |
console.log(res); | |
}, err => { | |
console.log(err); | |
}) | |
p.then(res => { | |
console.log(res); | |
}, err => { | |
console.log(err); | |
}) | |
console.log(p); |
# 异步任务
先执行宏队列,再执行微队列。
而 Promise 是异步的,所以先执行微队列,再执行宏队列。
核心步骤:
定义函数 => 调用核心API => 调用函数
const PENDING = 'pending' | |
const FULFILLED = 'fulfilled' | |
const REJECTED = 'rejected'; | |
class MyPromise { | |
state = PENDING; | |
result = undefined; | |
#handlers = []; // [{onFulfilled, onRejected}, 。。。] | |
constructor(executor) { | |
// 改状态: pending -> fulfilled | |
const resolve = (value) => { | |
if(this.state === PENDING) { | |
this.state = FULFILLED; | |
this.result = value; | |
// 执行回调 | |
this.#handlers.forEach(({onFulfilled}) => { | |
onFulfilled(this.result); | |
}) | |
} | |
} | |
// 改状态: pending -> rejected | |
const reject = (reason) => { | |
if(this.state === PENDING) { | |
this.state = REJECTED; | |
this.result = reason; | |
// 执行回调 | |
this.#handlers.forEach(({onRejected}) => { | |
onRejected(this.result); | |
}) | |
} | |
} | |
executor(resolve, reject); | |
} | |
then(onFulfilled, onRejected) { | |
// 如果 then 传入的参数不是函数,参考 MDN 文档返回 | |
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value; | |
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }; | |
if(this.state === FULFILLED) { | |
runAsynctask(() => { | |
onFulfilled(this.result); | |
}) | |
} else if(this.state === REJECTED) { | |
runAsynctask(() => { | |
onRejected(this.result); | |
}) | |
} else if(this.state === PENDING) { | |
this.#handlers.push({ | |
onFulfilled: () => { | |
runAsynctask(() => { | |
onFulfilled(this.result); | |
}) | |
}, | |
onRejected: () => { | |
runAsynctask(() => { | |
onRejected(this.result); | |
}) | |
} | |
}) | |
} | |
} | |
} | |
function runAsynctask(callback) { | |
if(typeof queueMicrotask === 'function') { | |
queueMicrotask(callback); | |
} else if(typeof MutationObserver === 'function') { | |
const obs = new MutationObserver(callback); | |
const divNode = document.createElement('div'); | |
obs.observe(divNode, {childList: true}) | |
divNode.innerText = '1'; | |
} else { | |
setTimeout(callback, 0); | |
} | |
} | |
const p = new MyPromise((resolve, reject) => { | |
resolve('success') | |
}) | |
p.then(res => { | |
console.log(res); | |
}) | |
console.log('end'); |
# 总结
- 构造函数
构造函数接收一个执行器函数executor
,该函数接收两个参数:resolve
和reject
。这两个函数分别用于将Promise
的状态从pending
转变为fulfilled
和rejected
。
class MyPromise { | |
state = PENDING; // 当前状态,默认为 pending | |
result = undefined; // 存储 resolve 或 reject 的结果 | |
#handlers = []; // 存储 then 方法中注册的回调函数 | |
constructor(executor) { | |
const resolve = (value) => { | |
if (this.state === PENDING) { // 确保状态只能从 pending 转变为 fulfilled | |
this.state = FULFILLED; | |
this.result = value; | |
// 触发所有已注册的 onFulfilled 回调 | |
this.#handlers.forEach(({ onFulfilled }) => { | |
onFulfilled(this.result); | |
}); | |
} | |
}; | |
const reject = (reason) => { | |
if (this.state === PENDING) { // 确保状态只能从 pending 转变为 rejected | |
this.state = REJECTED; | |
this.result = reason; | |
// 触发所有已注册的 onRejected 回调 | |
this.#handlers.forEach(({ onRejected }) => { | |
onRejected(this.result); | |
}); | |
} | |
}; | |
try { | |
executor(resolve, reject); | |
} catch (err) { | |
reject(err); // 如果执行器抛出异常,则直接调用 reject | |
} | |
} | |
} |
- then 方法
then
方法允许我们为Promise
注册成功和失败的回调函数。无论当前Promise
的状态是fulfilled
还是rejected
,then
方法都会触发相应的回调。如果Promise
仍然处于pending
状态,则会将回调存储起来,等到状态改变时再执行。
then(onFulfilled, onRejected) { | |
// 如果 then 的参数不是函数,则提供默认实现 | |
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value; | |
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }; | |
const p2 = new MyPromise((resolve, reject) => { | |
if (this.state === FULFILLED) { | |
runAsynctask(() => { | |
try { | |
const x = onFulfilled(this.result); | |
resolvePromise(p2, x, resolve, reject); | |
} catch (err) { | |
reject(err); | |
} | |
}); | |
} else if (this.state === REJECTED) { | |
runAsynctask(() => { | |
try { | |
const x = onRejected(this.result); | |
resolvePromise(p2, x, resolve, reject); | |
} catch (error) { | |
reject(error); | |
} | |
}); | |
} else if (this.state === PENDING) { | |
this.#handlers.push({ | |
onFulfilled: () => { | |
runAsynctask(() => { | |
try { | |
const x = onFulfilled(this.result); | |
resolvePromise(p2, x, resolve, reject); | |
} catch (err) { | |
reject(err); | |
} | |
}); | |
}, | |
onRejected: () => { | |
runAsynctask(() => { | |
try { | |
const x = onRejected(this.result); | |
resolvePromise(p2, x, resolve, reject); | |
} catch (err) { | |
reject(err); | |
} | |
}); | |
} | |
}); | |
} | |
}); | |
return p2; // 返回新的 Promise | |
} |
- 静态方法
为了方便使用,还实现了两个静态方法resolve
和reject
,它们可以快速创建一个已经或拒绝的Promise
static resolve(value) { | |
if (value instanceof MyPromise) { | |
return value; | |
} else { | |
return new MyPromise((resolve) => { | |
resolve(value); | |
}); | |
} | |
} | |
static reject(reason) { | |
return new MyPromise((resolve, reject) => { | |
reject(reason); | |
}); | |
} |
- 解析返回值函数
当then
方法中的回调函数返回一个值时,我们需要决定如何处理这个值。如果返回的是另一个Promise
,我们需要等待它的状态变化;否则,直接使用这个值作为新Promise
的结果
function resolvePromise(p2, x, resolve, reject) { | |
if (p2 === x) { | |
throw new TypeError('Chaining cycle detected for promise'); | |
} | |
if (x instanceof MyPromise) { | |
x.then(res => { | |
resolve(res); | |
}, (err) => { | |
reject(err); | |
}); | |
} else { | |
resolve(x); | |
} | |
} |
- 异步任务
为了确保回调函数总是异步执行,我们使用了一个辅助函数runAsynctask
来调度任务,优先尝试使用queueMicrotask
,如果不支持则回退到MutationObserver
或setTimeout
function runAsynctask(callback) { | |
if (typeof queueMicrotask === 'function') { | |
queueMicrotask(callback); | |
} else if (typeof MutationObserver === 'function') { | |
const obs = new MutationObserver(callback); | |
const divNode = document.createElement('div'); | |
obs.observe(divNode, { childList: true }); | |
divNode.innerText = '1'; | |
} else { | |
setTimeout(callback, 0); | |
} | |
} |
- 代码
// 三种状态 | |
const PENDING = 'pending' | |
const FULFILLED = 'fulfilled' | |
const REJECTED = 'rejected'; | |
class MyPromise { | |
state = PENDING; | |
result = undefined; | |
#handlers = []; // 存储 then 方法中注册的回调函数 [{onFulfilled, onRejected}, 。。。] | |
/** | |
* 构造函数,初始化 Promise | |
* @param {Function} executor - 执行器函数,接收 resolve 和 reject 作为参数 | |
*/ | |
constructor(executor) { | |
// 改状态: pending -> fulfilled | |
const resolve = (value) => { | |
if (this.state === PENDING) { // 确保状态只能从 pending -> fulfilled | |
this.state = FULFILLED; // 更新 | |
this.result = value; // 更新 | |
// 触发所有已注册的回调函数 | |
this.#handlers.forEach(({ onFulfilled }) => { | |
onFulfilled(this.result); | |
}) | |
} | |
} | |
// 改状态: pending -> rejected | |
const reject = (reason) => { | |
if (this.state === PENDING) { // 确保状态只能从 pending -> rejected | |
this.state = REJECTED; | |
this.result = reason; | |
// 触发所有已注册的回调函数 | |
this.#handlers.forEach(({ onRejected }) => { | |
onRejected(this.result); | |
}) | |
} | |
} | |
try { | |
// 执行用户传入的执行器函数,传入 resolve 和 reject | |
executor(resolve, reject); | |
} catch (err) { | |
// 如果执行器函数执行出错,则调用 reject | |
reject(err); | |
} | |
} | |
/** | |
* 注册成功和失败的回调函数 | |
* @param {Function} onFulfilled - 成功时的回调函数 | |
* @param {Function} onRejected - 失败时的回调函数 | |
* @returns {MyPromise} 返回一个新的 Promise 对象 | |
*/ | |
then(onFulfilled, onRejected) { | |
// 如果 then 传入的参数不是函数,参考 MDN 文档返回 | |
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value; | |
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }; | |
// 返回新的 promise | |
const p2 = new MyPromise((resolve, reject) => { | |
if (this.state === FULFILLED) { | |
// 当前状态为 fulfilled,则直接调用 onFulfilled | |
runAsynctask(() => { | |
try { | |
const x = onFulfilled(this.result); // 执行回调函数 | |
resolvePromise(p2, x, resolve, reject); // 解析回调函数的返回值 | |
} catch (err) { | |
reject(err); | |
} | |
}) | |
} else if (this.state === REJECTED) { | |
// 当前状态为 rejected,则直接调用 onRejected | |
runAsynctask(() => { | |
try { | |
const x = onRejected(this.result); // 执行回调函数 | |
resolvePromise(p2, x, resolve, reject); // 解析回调函数的返回值 | |
} catch (error) { | |
reject(error); | |
} | |
}) | |
} else if (this.state === PENDING) { | |
// 当前状态为 pending,则将回调函数存储起来,待状态改变时再执行 | |
this.#handlers.push({ | |
onFulfilled: () => { | |
runAsynctask(() => { | |
try { | |
const x = onFulfilled(this.result); | |
resolvePromise(p2, x, resolve, reject); | |
} catch (err) { | |
reject(err); | |
} | |
}) | |
}, | |
onRejected: () => { | |
runAsynctask(() => { | |
try { | |
const x = onRejected(this.result); | |
resolvePromise(p2, x, resolve, reject); | |
} catch (err) { | |
reject(err); | |
} | |
}) | |
} | |
}) | |
} | |
}); | |
return p2; // 返回新的 promise | |
} | |
/** | |
* 注册失败的回调函数 | |
* @param {Function} onRejected - 失败时的回调函数 | |
* @returns {MyPromise} 返回一个新的 Promise 对象 | |
*/ | |
catch(onRejected) { | |
return this.then(null, onRejected); | |
} | |
/** | |
* 注册无论成功或失败都会执行的回调函数 | |
* @param {Function} callback - 无论成功或失败都会执行的回调函数 | |
* @returns {MyPromise} 返回一个新的 Promise 对象 | |
*/ | |
finally(callback) { | |
return this.then(callback, callback); // 无论成功或失败都会执行 | |
} | |
/** | |
* 将传入的值转为一个 resolved 状态的 Promise | |
* @param {*} value - 需要转换的值 | |
* @returns {MyPromise} 返回一个 resolved 状态的 Promise | |
*/ | |
static resolve(value) { | |
if (value instanceof MyPromise) { | |
return value; // 如果已经是一个 Promise 对象,直接返回 | |
} else { | |
return new MyPromise((resolve) => { | |
resolve(value); // 转换为 resolved 状态 | |
}) | |
} | |
} | |
/** | |
* 返回一个 rejected 状态的 Promise | |
* @param {*} reason - 拒绝的原因 | |
* @returns {MyPromise} 返回一个 rejected 状态的 Promise | |
*/ | |
static reject(reason) { | |
return new MyPromise((resolve, reject) => { | |
reject(reason); // 创建一个新的 rejected Promise | |
}) | |
} | |
} | |
/** | |
* 解析 Promise 的返回值 x,并决定如何更新新的 Promise p2 的状态 | |
* @param {MyPromise} p2 - 新的 Promise 对象 | |
* @param {*} x - then 回调函数的返回值 | |
* @param {Function} resolve - p2 的 resolve 函数 | |
* @param {Function} reject - p2 的 reject 函数 | |
*/ | |
function resolvePromise(p2, x, resolve, reject) { | |
if (p2 === x) { | |
// 如果 x 是 p2 本身,抛出循环引用错误 | |
throw new TypeError('Chaining cycle detected for promise'); | |
} | |
if (x instanceof MyPromise) { | |
// 如果 x 是一个 Promise 递归解析状态 | |
x.then(res => { | |
resolve(res); | |
}, (err) => { | |
reject(err); | |
}) | |
} else { | |
resolve(x); | |
} | |
} | |
/** | |
* 异步执行任务(微任务优先) | |
* @param {Function} callback - 需要异步执行的任务 | |
*/ | |
function runAsynctask(callback) { | |
if (typeof queueMicrotask === 'function') { | |
queueMicrotask(callback); | |
} else if (typeof MutationObserver === 'function') { | |
const obs = new MutationObserver(callback); | |
const divNode = document.createElement('div'); | |
obs.observe(divNode, { childList: true }) | |
divNode.innerText = '1'; | |
} else { | |
setTimeout(callback, 0); | |
} | |
} |