Promise/A+标准
Promises/A+是一种用于标准化JavaScript中Promise对象行为的规范。
Promise对象状态:Pending(待定)、Fulfilled(已解决)和Rejected(已拒绝)。状态只能从Pending到Fulfilled或从Pending到Rejected,且一旦改变无法再次修改。
Promise对象可以使用resolve()函数将状态从Pending转换到Fulfilled,也可以使用reject()函数将状态从Pending转换到Rejected。
每个Promise必须有一个then方法,该方法接受两个参数:onFulfilled和onRejected,分别对应Promise成功和失败的情况。这些回调函数在Promise状态改变时被调用。
构造函数—constructor
constructor接收一个executor回调函数作为异步任务。在构造函数中初始化状态、值、回调函数栈,并定义resolve和reject函数传递给回调函数。当在异步任务中执行完成可以调用resolve/rejec,获取最终值。
#status:当前Promise的状态#value:Promise完成结果#reason:Promise拒绝原因#callBackStack:回调栈,用于存储每次调用then函数时传入的回调resolve():修改Promise的状态至Fulfilled,传递给executorreject():修改Promise的状态至Rejected,传递给executor#runAllCallbacks():执行回调栈中存储的回调方法(见下文实现)
class MyPromise {
#status;
#value;
#reason;
#callBackStack;
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.#status = MyPromise.PENDING;
this.#value = undefined;
this.#reason = undefined;
this.#callBackStack = [];
// resolve和reject不能写在原型上,this指向会受影响,指向window
const resolve = (value) => {
// 只有等待状态能够修改状态-2.1.1
// 当状态是完成时,不再处理-2.1.2
if (this.#status === MyPromise.PENDING) {
this.#status = MyPromise.FULFILLED;
this.#value = value;
// 状态变更后执行所有回调
this.#runAllCallbacks();
}
};
const reject = (reason) => {
// 只有等待状态能够修改状态-2.1.1
// 当状态是拒绝时,不再处理-2.1.3
if (this.#status === MyPromise.PENDING) {
this.#status = MyPromise.REJECTED;
this.#reason = reason;
// 状态变更后执行所有回调
this.#runAllCallbacks();
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
}
then函数
then()函数接收onFulfilled和onRejected函数,分别用于完成和拒绝的回调。then()函数返回一个新的Promise,并存储回调信息,在异步任务完成/拒绝时依次调用存储的回调函数。
onFulfilled():执行完成结果的回调,如果非函数则默认返回相同值onRejected():执行拒绝结果的回调,如果非函数则默认抛出相同错误#callBackStack:每次调用then就向栈里存储当前的回调信息,由于then可以多次调用,所以回调函数有多个,是个数组#runAllCallbacks():执行存储在栈中的所有回调函数,根据状态执行onFulfilled或onRejected#runSingleCallback():把单个回调放入微任务等待执行。如果回调函数结果是promise,需要根据返回的promise获取最终值
/**
* then方法,接收两个参数,onFulfilled和onRejected。
* 分别对应Promise的成功回调和失败回调。
* 如果这两个参数不是函数,则会被替换为默认的处理方式。
* 之后将回调信息添加到回调栈中,所有回调会在状态完成/拒绝后运行。
*
* @param {Function} onFulfilled - 成功回调
* @param {Function} onRejected - 失败回调
* @returns {MyPromise} 返回一个新的MyPromise对象
*/
then(onFulfilled, onRejected) {
// 处理onFulfilled/onRejected是非函数的情况
// onFulfilled 返回相同的值-2.2.7.3
// onRejected 返回相同的拒绝原因-2.2.7.4
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === "function"
? onRejected
: (reason) => {
throw reason;
};
return new MyPromise((resolve, reject) => {
// 记录then函数传递的回调信息
// 可能多次调用then,所以是一个数组-2.2.6
this.#callBackStack.push({ onFulfilled, onRejected, resolve, reject });
this.#runAllCallbacks();
});
}
/**
* 执行回调栈中存储的回调方法
* 首先判断状态,状态是完成/拒绝时才继续执行,并执行对应回调
*/
#runAllCallbacks() {
if (this.#status === MyPromise.PENDING) return;
while (this.#callBackStack.length) {
const { onFulfilled, onRejected, resolve, reject } =
this.#callBackStack.shift();
if (this.#status === MyPromise.FULFILLED) {
this.#runSingleCallback(onFulfilled, this.#value, resolve, reject);
} else {
this.#runSingleCallback(onRejected, this.#reason, resolve, reject);
}
}
}
/**
* 判断对象是否是Promise Like对象
* @param {Object/Function} obj - 需要被检测的对象
* @return {Boolean}
*/
#isPromiseLike(obj) {
if (obj !== null && (typeof obj === "object" || typeof obj === "function"))
return typeof obj.then === "function";
return false;
}
/**
* 在微队列中运行函数,根据运行环境的不同,选择不同的方式去执行传入的函数fn。
*
* @param {Function} fn - 需要被异步执行的函数
* 如果当前环境是Node.js,使用process.nextTick方法来异步执行;
* 如果当前环境是浏览器,使用MutationObserver来异步执行;
* 如果都不是上述环境,则使用setTimeout来异步执行。
*/
#runMicroTask(fn) {
if (typeof process === "object" && typeof process.nextTick === "function") {
// node环境
process.nextTick(fn);
} else if (typeof MutationObserver === "function") {
// 浏览器环境
const ob = new MutationObserver(fn);
const textNode = document.createTextNode("1");
ob.observe(textNode, {
characterData: true,
});
textNode.data = 2;
} else {
setTimeout(fn, 0);
}
}
/**
* 执行单个回调函数,首先运行一个微任务,然后尝试执行回调函数并处理其结果。
* 如果回调函数返回的结果是一个Promise对象,那么它将根据这个Promise的状态来决定是resolve还是reject。
* 如果回调函数执行过程中抛出异常,那么它将拒绝完成。
* @param {Function} callback - 回调函数
* @param {Any} value - 参数
* @param {Function} resolve - Promise对象的resolve方法
* @param {Function} reject - Promise对象的reject方法
*/
#runSingleCallback(callback, value, resolve, reject) {
this.#runMicroTask(() => {
try {
const result = callback(value);
if (this.#isPromiseLike(result)) {
// 回调函数返回结果是promise3 => 根据promise3状态执行resolve或rejected-2.3.2
result.then(resolve, reject);
} else {
// 回调是函数 => 执行回调,返回回调结果-2.3.3.3
resolve(result);
}
} catch (error) {
// 执行回调时存在异常 => 拒绝完成-2.2.7.2
reject(error);
}
});
}
其他方法
Promise/A+中没有规定的方法,可见MDN
catch函数
/**
* 处理Promise对象的拒绝状态的函数。当Promise对象被拒绝时,会调用这个函数。then函数的简写
* @param {Function} onRejected - 回调函数,用于处理Promise对象的拒绝状态
* @return {Promise} 返回一个新的MyPromise对象
*/
catch(onRejected) {
return this.then(undefined, onRejected);
}
finally函数
/**
* 无论是resolve还是reject,都会执行onFinally回调函数
* @param {Function} onFinally - 回调函数,在Promise结束时被调用
* @return {Promise} 返回一个新的MyPromise对象
*/
finally(onFinally) {
return this.then(
(data) => {
// onFinally 不接收任何参数,
// finally是透明的,即状态一致、返回相同的值-MDN finally描述第2、3点
onFinally();
return data;
},
(error) => {
onFinally();
throw error;
}
);
}
resolve函数
/**
* 静态方法,创建一个返回给定的值的已完成MyPromise对象。
* 如果传入的是一个MyPromise,则返回这个MyPromise;
* 如果输入值是类似Promise的对象(即拥有then方法),则使用其then方法来解析新的Promise;
* 如果不是,直接用输入值来完成新的Promise。
* @param {any} value - 值
* @return {MyPromise} 返回一个新的MyPromise对象
*/
static resolve(value) {
if (value instanceof MyPromise) return value;
let _resolve, _reject;
const p = new MyPromise((resolve, reject) => {
_resolve = resolve;
_reject = reject;
});
if (p.#isPromiseLike(value)) {
value.then(_resolve, _reject);
} else {
_resolve(value);
}
return p;
}
reject函数
/**
* 静态方法,创建一个返回给定原因的已拒绝的Promise对象。
*
* @param {any} reason - 拒绝原因
* @return {MyPromise} 返回一个新的MyPromise对象
*/
static reject(reason) {
return new MyPromise((_, reject) => {
reject(reason);
});
}
race函数
/**
* 静态方法,获取给定promise列表中最早完成或拒绝的promise
* @param {Array} promises - Promise对象数组
* @return {MyPromise} 返回一个新的PMyPromise对象
*/
static race(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
reject(new TypeError(`${promises} is not array`));
}
// 遍历所有promise
promises.forEach((promise) => {
// 可能包含非 promise 值,使用MyPromise.resolve
MyPromise.resolve(promise)
.then((data) => {
resolve(data);
})
.catch((error) => {
reject(error);
});
});
});
}
all函数
/**
* 静态方法,处理多个Promise。
* 如果所有Promise成功,返回一个包含所有结果的数组;
* 如果有一个Promise拒绝,返回第一个拒绝的Promise,并将第一个遇到的失败原因作为拒绝的原因。
* @param {Array} promises - Promise对象数组
* @returns {Promise} 返回一个新的Promise
*/
static all(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
reject(new TypeError(`${promises} is not array`));
}
let resolvedCount = 0; // promise完成个数
const result = new Array(promises.length); // 每个promise执行结果
promises.forEach((promise, index) => {
MyPromise.resolve(promise)
.then((data) => {
// 如果当前的promise执行成功,将结果存储到result中
resolvedCount++;
result[index] = data;
if (resolvedCount >= promises.length) {
resolve(result);
}
})
.catch((error) => {
reject(error);
});
});
});
}
any函数
/**
* 静态方法,接收一个Promise数组,并返回新的Promise。
* 当数组中任何Promise完成时,新的Promise就会立即完成,并返回第一个完成的Promise的结果。
* 如果所有的Promise都拒绝,那么新的Promise也会拒绝,并返回所有拒绝的原因。
* @param {Array} promises - Promise数组
* @returns {MyPromise} 返回一个新的Promise
* @throws {TypeError} 如果传入的参数不是一个数组,会抛出TypeError异常
* @throws {AggregateError} 如果所有的Promise都失败,会抛出一个AggregateError异常,该异常包含了所有失败的原因
*/
static any(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
reject(new TypeError(`${promises} is not array`));
}
if (!promises.length) {
// 空数组直接拒绝
reject(new AggregateError([], "All promises were rejected"));
return;
}
let rejectedCount = 0; // promise拒绝个数
const result = new Array(promises.length);
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
(data) => {
// 如果有完成的promise直接完成
resolve(data);
},
(error) => {
rejectedCount++;
result[index] = error;
if (rejectedCount >= promises.length) {
reject(new AggregateError(result, "All promises were rejected"));
}
}
);
});
});
}
allSettled函数
/**
* 静态方法,接收一个Promise数组,并返回新的Promise。
* 当数组的Promise都结束时,会返回一个数组,数组中含有所有Promise的结果
* @param {Array} promises - Promise数组
* @return {MyPromise} 返回一个新的Promise
*/
static allSettled(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
reject(new TypeError(`${promises} is not array`));
}
if (!promises.length) {
// 空数组直接完成
resolve([]);
return;
}
let count = 0;
const result = new Array(promises.length);
promises.forEach((promise, index) => {
MyPromise.resolve(promise)
.then(
(value) => {
result[index] = { status: MyPromise.FULFILLED, value };
},
(reason) => {
result[index] = { status: MyPromise.REJECTED, reason };
}
)
.finally(() => {
count++;
if (count >= promises.length) resolve(result);
});
});
});
}
测试
then链式调用:
const p = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve("success1");
}, 1000);
});
p.then((data) => {
console.log("then1", data);
return "success2";
}).then((data) => {
console.log("then2", data);
});
// 结果:
// then1 success1
// then2 success2
then返回原生promise:
const p = new MyPromise((resolve) => {
setTimeout(() => {
resolve(1);
}, 1000);
});
p.then((data) => {
console.log("then1", data);
return new Promise((resolve) => {
setTimeout(() => {
resolve(2), 1000;
});
});
}).then((data) => {
console.log("then1", data);
});
// 结果:
// then1 1
// then2 2
async/await使用:
const delay = (ms = 1000) => {
return new MyPromise((resolve) => {
setTimeout(() => {
resolve("延时结束");
}, ms);
});
};
const test = async () => {
const result = await delay();
console.log("result", result);
console.log(1);
};
test();
// 结果:
// result 延时结束
// 1
微队列:
setTimeout(() => {
console.log(1);
}, 0);
new MyPromise((resolve) => {
console.log(2);
resolve(3);
}).then((data) => {
console.log(3);
});
// 结果:2 3 1
race、all、any、allSettled函数:
const p1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
// resolve("p1");
reject("p1");
}, 1000);
});
const p2 = new MyPromise((resolve) => {
setTimeout(() => {
resolve("p2");
}, 2000);
});
MyPromise.race([p1, p2]).then(
(data) => {
console.log("data", data);
},
(error) => {
console.log("error", error);
}
);
MyPromise.all([p1, p2]).then(
(data) => {
console.log("data", data);
},
(error) => {
console.log("error", error);
}
);
MyPromise.any([p1, p2]).then(
(data) => {
console.log("data", data);
},
(error) => {
console.log("error", error);
}
);
MyPromise.allSettled([p1, p2]).then(
(data) => {
console.log("data", data);
},
(error) => {
console.log("error", error);
}
);
// 结果:
// error p1
// error p1
// data p2
// data [({ status: "rejected", reason: "p1" }, { status: "fulfilled", value: "p2" })];
MyPromise
class MyPromise {
#status;
#value;
#reason;
#callBackStack;
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.#status = MyPromise.PENDING;
this.#value = undefined;
this.#reason = undefined;
this.#callBackStack = [];
// resolve和reject不能写在原型上,this指向会受影响,指向window
const resolve = (value) => {
// 只有等待状态能够修改状态-2.1.1
// 当状态是完成时,不再处理-2.1.2
if (this.#status === MyPromise.PENDING) {
this.#status = MyPromise.FULFILLED;
this.#value = value;
// 状态变更后执行所有回调
this.#runAllCallbacks();
}
};
const reject = (reason) => {
// 只有等待状态能够修改状态-2.1.1
// 当状态是拒绝时,不再处理-2.1.3
if (this.#status === MyPromise.PENDING) {
this.#status = MyPromise.REJECTED;
this.#reason = reason;
// 状态变更后执行所有回调
this.#runAllCallbacks();
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
/**
* 执行回调栈中存储的回调方法
* 首先判断状态,状态是完成/拒绝时才继续执行,并执行对应回调
*/
#runAllCallbacks() {
if (this.#status === MyPromise.PENDING) return;
while (this.#callBackStack.length) {
const { onFulfilled, onRejected, resolve, reject } =
this.#callBackStack.shift();
if (this.#status === MyPromise.FULFILLED) {
this.#runSingleCallback(onFulfilled, this.#value, resolve, reject);
} else {
this.#runSingleCallback(onRejected, this.#reason, resolve, reject);
}
}
}
/**
* 判断对象是否是Promise Like对象
* @param {Object/Function} obj - 需要被检测的对象
* @return {Boolean}
*/
#isPromiseLike(obj) {
if (obj !== null && (typeof obj === "object" || typeof obj === "function"))
return typeof obj.then === "function";
return false;
}
/**
* 在微队列中运行函数,根据运行环境的不同,选择不同的方式去执行传入的函数fn。
*
* @param {Function} fn - 需要被异步执行的函数
* 如果当前环境是Node.js,使用process.nextTick方法来异步执行;
* 如果当前环境是浏览器,使用MutationObserver来异步执行;
* 如果都不是上述环境,则使用setTimeout来异步执行。
*/
#runMicroTask(fn) {
if (typeof process === "object" && typeof process.nextTick === "function") {
// node环境
process.nextTick(fn);
} else if (typeof MutationObserver === "function") {
// 浏览器环境
const ob = new MutationObserver(fn);
const textNode = document.createTextNode("1");
ob.observe(textNode, {
characterData: true,
});
textNode.data = 2;
} else {
setTimeout(fn, 0);
}
}
/**
* 执行单个回调函数,首先运行一个微任务,然后尝试执行回调函数并处理其结果。
* 如果回调函数返回的结果是一个Promise对象,那么它将根据这个Promise的状态来决定是resolve还是reject。
* 如果回调函数执行过程中抛出异常,那么它将拒绝完成。
* @param {Function} callback - 回调函数
* @param {Any} value - 参数
* @param {Function} resolve - Promise对象的resolve方法
* @param {Function} reject - Promise对象的reject方法
*/
#runSingleCallback(callback, value, resolve, reject) {
this.#runMicroTask(() => {
try {
const result = callback(value);
if (this.#isPromiseLike(result)) {
// 回调函数返回结果是promise3 => 根据promise3状态执行resolve或rejected-2.3.2
result.then(resolve, reject);
} else {
// 回调是函数 => 执行回调,返回回调结果-2.3.3.3
resolve(result);
}
} catch (error) {
// 执行回调时存在异常 => 拒绝完成-2.2.7.2
reject(error);
}
});
}
/**
* then方法,接收两个参数,onFulfilled和onRejected。
* 分别对应Promise的成功回调和失败回调。
* 如果这两个参数不是函数,则会被替换为默认的处理方式。
* 之后将回调信息添加到回调栈中,所有回调会在状态完成/拒绝后运行。
*
* @param {Function} onFulfilled - 成功回调
* @param {Function} onRejected - 失败回调
* @returns {MyPromise} 返回一个新的MyPromise对象
*/
then(onFulfilled, onRejected) {
// 处理onFulfilled/onRejected是非函数的情况
// onFulfilled 返回相同的值-2.2.7.3
// onRejected 返回相同的拒绝原因-2.2.7.4
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === "function"
? onRejected
: (reason) => {
throw reason;
};
return new MyPromise((resolve, reject) => {
// 记录then函数传递的回调信息
// 可能多次调用then,所以是一个数组-2.2.6
this.#callBackStack.push({ onFulfilled, onRejected, resolve, reject });
this.#runAllCallbacks();
});
}
/**
* 处理Promise对象的拒绝状态的函数。当Promise对象被拒绝时,会调用这个函数。then函数的简写
* @param {Function} onRejected - 回调函数,用于处理Promise对象的拒绝状态
* @return {Promise} 返回一个新的MyPromise对象
*/
catch(onRejected) {
return this.then(undefined, onRejected);
}
/**
* 无论是resolve还是reject,都会执行onFinally回调函数
* @param {Function} onFinally - 回调函数,在Promise结束时被调用
* @return {Promise} 返回一个新的MyPromise对象
*/
finally(onFinally) {
return this.then(
(data) => {
// onFinally 不接收任何参数,
// finally是透明的,即状态一致、返回相同的值-MDN finally描述第2、3点
onFinally();
return data;
},
(error) => {
onFinally();
throw error;
}
);
}
/**
* 静态方法,创建一个返回给定的值的已完成MyPromise对象。
* 如果传入的是一个MyPromise,则返回这个MyPromise;
* 如果输入值是类似Promise的对象(即拥有then方法),则使用其then方法来解析新的Promise;
* 如果不是,直接用输入值来完成新的Promise。
* @param {any} value - 值
* @return {MyPromise} 返回一个新的MyPromise对象
*/
static resolve(value) {
if (value instanceof MyPromise) return value;
let _resolve, _reject;
const p = new MyPromise((resolve, reject) => {
_resolve = resolve;
_reject = reject;
});
if (p.#isPromiseLike(value)) {
value.then(_resolve, _reject);
} else {
_resolve(value);
}
return p;
}
/**
* 静态方法,创建一个返回给定原因的已拒绝的Promise对象。
*
* @param {any} reason - 拒绝原因
* @return {MyPromise} 返回一个新的MyPromise对象
*/
static reject(reason) {
return new MyPromise((_, reject) => {
reject(reason);
});
}
/**
* 静态方法,获取给定promise列表中最早完成或拒绝的promise
* @param {Array} promises - Promise对象数组
* @return {MyPromise} 返回一个新的PMyPromise对象
*/
static race(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
reject(new TypeError(`${promises} is not array`));
}
// 遍历所有promise
promises.forEach((promise) => {
// 可能包含非 promise 值,使用MyPromise.resolve
MyPromise.resolve(promise)
.then((data) => {
resolve(data);
})
.catch((error) => {
reject(error);
});
});
});
}
/**
* 静态方法,处理多个Promise。
* 如果所有Promise成功,返回一个包含所有结果的数组;
* 如果有一个Promise拒绝,返回第一个拒绝的Promise,并将第一个遇到的失败原因作为拒绝的原因。
* @param {Array} promises - Promise对象数组
* @returns {Promise} 返回一个新的Promise
*/
static all(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
reject(new TypeError(`${promises} is not array`));
}
let resolvedCount = 0; // promise完成个数
const result = new Array(promises.length); // 每个promise执行结果
promises.forEach((promise, index) => {
MyPromise.resolve(promise)
.then((data) => {
// 如果当前的promise执行成功,将结果存储到result中
resolvedCount++;
result[index] = data;
if (resolvedCount >= promises.length) {
resolve(result);
}
})
.catch((error) => {
reject(error);
});
});
});
}
/**
* 静态方法,接收一个Promise数组,并返回新的Promise。
* 当数组中任何Promise完成时,新的Promise就会立即完成,并返回第一个完成的Promise的结果。
* 如果所有的Promise都拒绝,那么新的Promise也会拒绝,并返回所有拒绝的原因。
* @param {Array} promises - Promise数组
* @returns {MyPromise} 返回一个新的Promise
* @throws {TypeError} 如果传入的参数不是一个数组,会抛出TypeError异常
* @throws {AggregateError} 如果所有的Promise都失败,会抛出一个AggregateError异常,该异常包含了所有失败的原因
*/
static any(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
reject(new TypeError(`${promises} is not array`));
}
if (!promises.length) {
// 空数组直接拒绝
reject(new AggregateError([], "All promises were rejected"));
return;
}
let rejectedCount = 0; // promise拒绝个数
const result = new Array(promises.length);
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
(data) => {
// 如果有完成的promise直接完成
resolve(data);
},
(error) => {
rejectedCount++;
result[index] = error;
if (rejectedCount >= promises.length) {
reject(new AggregateError(result, "All promises were rejected"));
}
}
);
});
});
}
/**
* 静态方法,接收一个Promise数组,并返回新的Promise。
* 当数组的Promise都结束时,会返回一个数组,数组中含有所有Promise的结果
* @param {Array} promises - Promise数组
* @return {MyPromise} 返回一个新的Promise
*/
static allSettled(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
reject(new TypeError(`${promises} is not array`));
}
if (!promises.length) {
// 空数组直接完成
resolve([]);
return;
}
let count = 0;
const result = new Array(promises.length);
promises.forEach((promise, index) => {
MyPromise.resolve(promise)
.then(
(value) => {
result[index] = { status: MyPromise.FULFILLED, value };
},
(reason) => {
result[index] = { status: MyPromise.REJECTED, reason };
}
)
.finally(() => {
count++;
if (count >= promises.length) resolve(result);
});
});
});
}
}