Promise 对象表示异步操作最终的完成(或失败)以及其结果值。
一个 Promise 是一个代理,它代表一个在创建 promise 时不一定已知的值,它允许你将处理程序与异步操作的最终成功值或失败原因关联起来。这使得异步方法可以像同步方法一样返回值:异步方法不会立即返回最终值,而是返回一个 promise,以便在将来的某个时间点提供该值。
一个 Promise 必然处于以下几种状态之一:
- 待定(pending) :初始状态,既没有被兑现,也没有被拒绝
- 已兑现(fulfilled) :意味着操作成功完成
- 已拒绝(rejected) :意味着操作失败
一个待定的 Promise 最终状态 可以是已兑现 并返回一个值,或者是已拒绝 并返回一个原因(错误)。当其中任意一种情况发生时,通过 Promise 的 then
方法串联的处理程序将被调用。
1. Promise.all
Promise.all() 静态方法接受一个 Promise 可迭代对象作为输入,并返回一个 Promise。当所有输入的 Promise 都被兑现时,返回的 Promise 也将被兑现(即使传入的是一个空的可迭代对象),并返回一个包含所有兑现值的数组;如果输入的任何 Promise 被拒绝,则返回的 Promise 将被拒绝,并带有第一个被拒绝的原因。
js
Promise._all = (iterObj) => {
// 1. iterObj 必须是一个可迭代对象, 否则, 无法正常进行则抛出错误
if(!(typeof iterObj === "object" && iterObj !== null && typeof iterObj[Symbol.iterator] === "function")){
throw new TypeError(`${iterObj} is not iterable`);
}
iterObj = [...iterObj];
/*
* 2. 函数返回值为 `<Promise>` 对象, 当参数 `iterObj` 内所有的 `Promise` 成功,
* 该 `<Promise>` 对象成功, 成功数据为所有成功的 `Promise` 结果数组,
* 有一个不成功, 则该 `<Promise>` 不成功, 失败数据为失败原因字符串
*/
return new Promise((resolve, reject) => {
const len = iterObj.length;
let count = 0;
if(len === 0) return resolve([]);
const res = new Array(len);
iterObj.forEach(async (item, index) => {
const newItem = Promise.resolve(item);
try{
const result = await newItem;
res[index] = result;
if(++count === len){
resolve(res)
}
}catch(err){
reject(err);
}
})
})
}
测试验证:
js
// 验证:
function test(){
try{
Promise._all(null).then(res=>console.log(res), rej=>console.log(rej));
// throw err: null is not iterable
}catch(e){
console.log(e)
}
try{
Promise._all({}).then(res=>console.log(res), rej=>console.log(rej));
// throw err: [object object] is not iterable
}catch(e){
console.log(e)
}
Promise._all([]).then(res=>console.log(res), rej=>console.log(rej));
// []
Promise._all(new Set()).then(res=>console.log(res), rej=>console.log(rej));
// []
Promise._all(new Map()).then(res=>console.log(res), rej=>console.log(rej));
// []
Promise._all([
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3),
4,
]).then(res=>console.log(res), rej=>console.log(rej))
// [1, 2, 3, 4]
Promise._all([
Promise.reject(1),
Promise.resolve(2),
Promise.resolve(3),
4,
]).then(res=>console.log(res), rej=>console.log(rej))
// 1
}
test();
2. Promise.prototype.catch
Promise
实例的 catch() 方法用于注册一个在 promise 被拒绝时调用的函数,它会立即返回一个等效的 Promise 对象,这可以允许你链式调用其他 promise 的方法。
此方法是 Promise.prototype.then(undefined, onRejected) 的一种简写形式。
js
/**
* 本质就是then,只是少传了一个onFulfilled
* 所以仅处理失败的场景
* @param {*} onRejected
*/
Promise.prototype.catch = function(onRejected) {
return this.then(null, onRejected);
}
3. Promise.race
Promise.race() 静态方法接受一个 promise 可迭代对象作为输入,并返回一个 Promise,这个返回的 promise 会随着第一个 promise 的敲定而敲定。
js
Promise._race = function (promises) {
if(!(typeof promises === "object" && promises !== null && typeof promises[Symbol.iterator] === "function")){
throw new TypeError(`${promises} is not iterable`);
}
promises = [...promises];
return new Promise((resolve, reject) => {
for (let p of promises) {
Promise.resolve(p).then(resolve).catch(reject);
}
});
};
4. Promise.allSettled
Promise.allSettled() 静态方法将一个 Promise 可迭代对象作为输入,并返回一个单独的 Promise。当所有输入的 Promise 都已敲定时(包括传入空的可迭代对象时),返回的 Promise 将被兑现,并带有描述每个 Promise 结果的对象数组。
js
Promise.prototype.mySettled = function (promises) {
return new Promise((resolve) => {
const data = [],
len = promises.length;
let cnt = 0;
for (let i = 0; i < len; i++) {
const promise = promises[i];
Promise.resolve(promise)
.then(
(res) => {
data[i] = { status: "fulfilled", value: res };
},
(error) => {
data[i] = { status: "rejected", reason: error };
}
)
.finally(() => {
if (cnt === len) resolve(data);
});
}
});
};
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) =>
setTimeout(reject, 100, "foo")
);
const promises = [promise2, promise1];
Promise.allSettled(promises).then((results) =>
results.forEach((result) => console.log(result))
);
5. Promise.reject
Promise.reject() 静态方法返回一个已拒绝(rejected)的 Promise 对象,拒绝原因为给定的参数。
js
Promise._reject = function(reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
});
}
6. Promise.resolve
Promise.resolve() 静态方法将给定的值转换为一个 Promise
,如果该值本身就是一个 Promise,那么该 Promise 将被返回;如果该值是一个 thenable 对象,Promise.resolve() 将调用其 then()
方法及其两个回调函数;否则,返回的 Promise 将会以该值兑现。
该函数将嵌套的类 Promise 对象(例如,一个将被兑现为另一个 Promise 对象的 Promise 对象)展平,转化为单个 Promise 对象,其兑现值为一个非 thenable 值。
js
Promise._resolve = function(value) {
// 如果 value 已经是 Promise 对象,则直接返回该 Promise 对象
if (value && value instanceof Promise) {
return value;
}
// 如果 value 是 thenable 对象,则包装成 Promise 对象并返回
if (value && typeof value.then === 'function') {
return new Promise(function(resolve, reject) {
value.then(resolve, reject);
});
}
// 将传入的值作为 Promise 的成功值,并返回 Promise 对象
return new Promise(function(resolve) {
resolve(value);
});
}
7. Promise.prototype.finally
Promise
实例的 finally() 方法用于注册一个在 promise 敲定(兑现或拒绝)时调用的函数。它会立即返回一个等效的 Promise
对象,这可以允许你链式调用其他 promise 方法;这可以让你避免在 promise 的 then()
和 catch()
处理器中重复编写代码。
js
/**
* 无论成功还是失败都会执行回调
* @param {Function} onSettled
*/
Promise.prototype.finally = function (onSettled) {
return this.then(
(data) => {
onSettled(); // 实现了收不到参数了
return data;
},
(reason) => {
onSettled();
throw reason;
}
);
// finally函数 返回结果应该是无效的
}
/******test finally*******/
// 无论什么结果,都会运行
const pro = new Promise((resolve, reject) => {
resolve(1);
});
const pro2 = pro.finally((d) => {
console.log("finally", d); // 收不到d参数
// 本身不改变状态,但是抛出一个错误,数据就会变成它的错误
// throw 123;
return 123; //不起作用
});
setTimeout(() => {
console.log(pro2);
});