Promise笔记
是什么
- 语法上:Promise是由new Promise()构造函数构造得来的Promise对象。
- 功能上:Promise是异步函数的解决方案
案例理解
const p1 = new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('fail')), 3000)
})
const p2 = new Promise(function (resolve, reject) {
setTimeout(() => resolve(p1), 1000)
})
console.time('执行用时');
p2
.then(result => console.log('result is' + result))
.catch(error => {
console.log(error)
console.timeEnd('执行用时');
})
// Error: fail
// at Timeout._onTimeout (c:\Users\HUAWEI\Desktop\index.js:27:29)
// at listOnTimeout (node:internal/timers:569:17)
// at process.processTimers (node:internal/timers:512:7)
// 执行用时: 3.025s上面代码中,
p1是一个 Promise,3 秒之后变为rejected。p2的状态在 1 秒之后改变,resolve方法返回的是p1。由于p2返回的是另一个 Promise,导致p2自己的状态无效了,由p1的状态决定p2的状态。所以,后面的then语句都变成针对后者(p1)。又过了 2 秒,p1变为rejected,导致触发catch方法指定的回调函数。
p2调用时,resolve(p1)函数立即执行,由于p2返回的是一个Promise,那么p2自己的状态无效,决定于p1的状态,然后看p1,p1立即执行reject()函数,reject函数将Error实例返回,等待3s后,p1状态变为rejected,p2的状态同样变为rejected,于是到catch里面。函数总共用了3s
const promise = new Promise((resolve, reject) => {
// ... some code
console.log("hello Promise");
const RandNumber = Math.random() * 2;
console.log(`Waiting ${RandNumber} seconds!`);
setTimeout(() => {
if (RandNumber >= 1) {
resolve(`Resolve this value: ${RandNumber}, Success!`);
} else {
reject(`Reject this value: ${RandNumber}, Failed!`);
}
}, RandNumber * 1000);
});
promise.then(
(value) => {
// success
console.log(value);
},
(error) => {
// failure
console.log(error);
}
).catch(error => {
console.log('我不执行');
console.log(error);
}); p2
.then(result => console.log('result is' + result))
.catch(error => {
console.log(error)
console.timeEnd('执行用时');
})对比两个实例,都是promise.then.catch链式调用,不过有所不同。
- p2的.then调用返回的是Promise实例p1,.catch用于捕捉p1的reject。
- promise不返回另一个promise,状态由自身决定,所以.catch作为.then的链式调用,捕捉.then方法的error,当then方法执行有误时,会捕捉成功。注意,then方法返回的是一个新的Promise(使得.then.then方法能够链式调用)
promise.then(
(value) => {
// success
console.log(value);
console.log(v);
},
(error) => {
// failure
console.log(error);
}
).catch(error => {
console.log('我会在then方法执行success的时候执行,因为v变量未声明');
console.log(error);
});getJSON('/posts.json').then(function(posts) {
// ...
}).catch(function(error) {
// 处理 getJSON 和 前一个回调函数运行时发生的错误
console.log('发生错误!', error);
});上面代码中,
getJSON()方法返回一个 Promise 对象,如果该对象状态变为resolved,则会调用then()方法指定的回调函数;如果异步操作抛出错误,状态就会变为rejected,就会调用catch()方法指定的回调函数,处理这个错误。另外,then()方法指定的回调函数,如果运行中抛出错误,也会被catch()方法捕获。
Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个
catch语句捕获。
getJSON('/post/1.json').then(function(post) {
return getJSON(post.commentURL);
}).then(function(comments) {
// some code
}).catch(function(error) {
// 处理前面三个Promise产生的错误
});上面代码中,一共有三个 Promise 对象:一个由
getJSON()产生,两个由then()产生。它们之中任何一个抛出的错误,都会被最后一个catch()捕获。一般来说,不要在
then()方法里面定义 Reject 状态的回调函数(即then的第二个参数),总是使用catch方法。
// bad
promise
.then(function(data) {
// success
}, function(err) {
// error
});
// good
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});为什么
Promise用来处理异步操作,避免了回调地狱的出现。
怎么用
Promise.prototype.then()方法
getJSON("/post/1.json").then(
post => getJSON(post.commentURL)
).then(
comments => console.log("resolved: ", comments),
err => console.log("rejected: ", err)
);Promise.prototype.catch()
// 实际上是then()方法的特殊形式
p.then((val) => console.log('fulfilled:', val))
.catch((err) => console.log('rejected', err));
// 等同于
p.then((val) => console.log('fulfilled:', val))
.then(null, (err) => console.log("rejected:", err));
// 除此之外,catch方法可以捕获Promise方法,then()方法抛出的错误,而且catch方法遵守冒泡规则,可以捕获若干个之前的promise方法,then()方法抛出的错误
getJSON('/post/1.json').then(function(post) {
return getJSON(post.commentURL);
}).then(function(comments) {
// some code
}).catch(function(error) {
// 处理前面三个Promise产生的错误:getJSON方法(其被处理成promise方法),以及两个.then方法
});Promise.prototype.finally()
// 其不管promise是resolved还是rejected都会执行
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});Promise.all()
// 其接收一个数组,按顺序执行,如果如果p1, p2, p3的状态都变成fulfilled,p的状态才会变成fulfilled,当这个数组中有一个promise的状态变成rejected,p的状态立即变为rejected,并且立即执行.catch()方法
const p = Promise.all([p1, p2, p3]);Promise.race()
// Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3]);
// 上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。Promise.allSettled()
// 前面的all()方法和race()方法行使了且、或的功能,但是还不够全面,且的方法有一个reject
// 时,就不关心其他的结果了,有没有一种方法,就是等到所有方法终止了才执行
const p = Promise.allSettled([p1, p2, p3]);
// 上面示例中,数组promises包含了三个请求,只有等到这三个请求都结束了(不管请求成功还是失败),removeLoadingIndicator()才会执行。
// 该方法返回的新的 Promise 实例,一旦发生状态变更,状态总是fulfilled,不会变成rejected。状态变成fulfilled后,它的回调函数会接收到一个数组作为参数,该数组的每个成员对应前面数组的每个 Promise 对象。
// 其当然能够监测每一个结果的状态:
const resolved = Promise.resolve(42);
const rejected = Promise.reject(-1);
const allSettledPromise = Promise.allSettled([resolved, rejected]);
allSettledPromise.then(function (results) {
console.log(results);
});
// [
// { status: 'fulfilled', value: 42 },
// { status: 'rejected', reason: -1 }
// ]Promise.any()
// Promise.race()方法获得一组异步操作方法中第一个结束的异步操作的结果,并作为新的Promise结果返回,有没有一种方法,是希望Promise成功的,只要有一个promise是fulfilled状态,返回fulfilled,只有当全部的promise都是rejected,才返回rejected
const p = Promise.any([p1, p2, p3]);Promise.resolve()
// 1.如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
// 2.thenable对象指的是具有then方法的对象,比如下面这个对象。
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
// Promise.resolve()方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then()方法。
// 上面代码中,thenable对象的then()方法执行后,对象p1的状态就变为resolved,从而立即执行最后那个then()方法指定的回调函数,输出42。
// 3. 如果参数是一个原始值,或者是一个不具有then()方法的对象,则Promise.resolve()方法返回一个新的 Promise 对象,状态为resolved。
// 4. Promise.resolve()方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。Promise.reject()
const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))
p.then(null, function (s) {
console.log(s)
});
// 出错了
//上面代码生成一个 Promise 对象的实例p,状态为rejected,回调函数会立即执行。
// Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。
Promise.reject('出错了')
.catch(e => {
console.log(e === '出错了')
})
// true
// 上面代码中,Promise.reject()方法的参数是一个字符串,后面catch()方法的参数e就是这个字符串。Promise.try()
Promise.try(() => database.users.get({id: userId}))
.then(...)
.catch(...)
// 事实上,Promise.try就是模拟try代码块,就像promise.catch模拟的是catch代码块。怎么实现
如何手写一个Promise?在ES6之前
跟着bili视频写了一遍,这是没有用class的版本
// const promise = new Promise((resolve, reject) => {
// // ... some code
// console.log("hello Promise");
// const RandNumber = Math.random() * 2;
// console.log(`Waiting ${RandNumber} seconds!`);
// setTimeout(() => {
// if (RandNumber >= 1) {
// resolve(`Resolve this value: ${RandNumber}, Success!`);
// } else {
// reject(`Reject this value: ${RandNumber}, Failed!`);
// }
// }, RandNumber * 1000);
// });
// promise.then(
// (value) => {
// // success
// console.log(value);
// console.log(v);
// },
// (error) => {
// // failure
// console.log(error);
// return new Error('捕捉失败的Error');
// }
// ).catch(error => {
// console.log('我不执行');
// console.log(error);
// });
// const p1 = new Promise(function (resolve, reject) {
// setTimeout(() => reject(new Error('fail')), 3000)
// })
// const p2 = new Promise(function (resolve, reject) {
// setTimeout(() => resolve(p1), 1000)
// })
// console.time('执行用时');
// p2
// .then(result => console.log('result is' + result))
// .catch(error => {
// console.log(error)
// console.timeEnd('执行用时');
// })
// const promise = new Promise(function (resolve, reject) {
// resolve('ok');
// setTimeout(function () { throw new Error('test') }, 0)
// });
// promise.then(function (value) { console.log(value) });
// const resolved = Promise.resolve(42);
// const rejected = Promise.reject(-1);
// const allSettledPromise = Promise.allSettled([resolved, rejected]);
// allSettledPromise.then(function (results) {
// console.log(results);
// });
// [
// { status: 'fulfilled', value: 42 },
// { status: 'rejected', reason: -1 }
// ]
// let thenable = {
// then: function(resolve, reject) {
// resolve(42);
// }
// };
// let p1 = Promise.resolve(thenable);
// // p1.then(function (value) {
// // console.log(value); // 42
// // });
// 手写Promise
// // 1. 创建Promise实例化对象
// let p = new myPromise((resolve, reject) => {
// console.log("this is a executor");
// resolve(42);
// // reject(666)
// });
// let p2 = p.then(
// (value) => {
// // 对应没有返回值START
// console.log(`p.then()方法调用了!结果是value: ${value}`);
// // 对应没有返回值END
// // // 对应返回值为非promise对象 START
// // return [1,2,3]
// // // 对应返回值为非promise对象 END
// // 对应返回值为error
// // throw "errorere";
// // 对应返回值为promise对象 START
// // return new myPromise((resolve, reject) => {
// // // 返回promise-resolve
// // // resolve('okok')
// // // 返回promise-reject
// // // reject('nonono')
// // // 返回promise-error
// // // throw 'error'
// // })
// // 对应返回值为promise对象 END
// },
// (reason) => console.log(`p.then()方法调用了!结果是reason: ${reason}`)
// );
// console.log("同步执行的这一句应该显示在p.then()方法之前");
// setTimeout(() => {
// console.log(p2);
// }, 1000);
// const p1 = new myPromise((resolve, reject) => {
// // resolve(199)
// // reject('nonononon')
// // throw 'err'
// // throw new Error('Err')
// setTimeout(() => {
// // console.log('我的网络很慢,发送这个请求需要3s,在此之前状态应该是pending');
// // resolve(100);
// reject('rrr')
// }, 1000);
// // resolve(100)
// });
// const p2 = p1.catch(reason => {
// // console.log(`catch方法, ${reason}`);
// // return reason
// // throw new Error('fdjsalkfdasdsa')
// })
// console.log(p2);
// setTimeout(() => {
// console.log(p2);
// }, 2000)
// new myPromise((resolve, reject) => {
// resolve(1)
// // reject('eororsre')
// }).then(value => {
// throw '异常'
// }).then(value => {
// console.log(value);
// return 3
// }).then(value => {
// console.log(value);
// return 4
// }).then(value => {
// console.log(value);
// return 5
// }).catch(reason => {
// console.log(reason);
// })
// 15 promise.resolve方法
myPromise.resolve = function(value) {
if (value instanceof myPromise) {
return value
} else {
return new myPromise(resolve => {
resolve(value)
})
}
}
// 16. promise.reject方法,始终返回一个失败的promise方法
myPromise.reject = function(value) {
return new myPromise((undefined, reject) => {
reject(value)
})
}
// 17. promise.all方法,接收一个函数数组,按顺序执行这个函数数组,
// 如果所有的都是fulfilled,返回一个promise,result是一个数组,内容是函数数组执行的结果
// 如果有一个是rejected,直接返回promise, result是reject的值
myPromise.all = function(promiseArr) {
let result = new Array(promiseArr.length)
let index = 0
return new Promise((resolve, reject) => {
promiseArr.forEach((item, i, arr) => {
item.then(value => {
index++
// result.push(value)
result[i] = value
if(index === promiseArr.length) resolve(result)
}, reason => {
// 如果失败,直接拒绝
reject(reason)
})
})
// resolve(result)
})
}
myPromise.race = function(promiseArr) {
return new myPromise((resolve, reject) => {
promiseArr.forEach(item => {
item.then(value => {
resolve(value)
}, reason => {
reject(reason)
})
})
})
}
myPromise.allSettled = function(promiseArr) {
let result = []
let count = 0
return new myPromise((resolve, reject) => {
promiseArr.forEach(item => {
item.then(value => {
result.push({
status: 'fulfilled', value
})
count++
if (count === promiseArr.length) {
resolve(result)
}
}, reason => {
result.push({
status: 'rejected', reason
})
count++
if (count === promiseArr.length) {
resolve(result)
}
})
})
})
}
myPromise.any = function(promiseArr) {
let errors = []
let count = 0
return new myPromise((resolve, reject) => {
promiseArr.forEach((item, index) => {
item.then(value => {
resolve(value)
}, reason => {
errors[index] = reason
count++
// !不仅要在forEach里面检测,而且还要在处理错误的时候检测。在外面是同步的,无法等待结果
if (count === promiseArr.length) {
reject(new AggregateError(errors, "All promises were rejected"))
}
})
})
})
}
// const p1 = myPromise.resolve(1)
// console.log(p1);
// const p2 = myPromise.resolve(new myPromise((resolve, reject) => {
// resolve(2)
// }))
// console.log(p2);
// const p3 = myPromise.resolve(new myPromise((resolve, reject) => {
// reject(3)
// }))
// console.log(p3);
// const p1 = myPromise.reject(1)
// console.log(p1);
const p1 = new myPromise((resolve, reject) => {
setTimeout(() => {
reject(100)
}, 100)
})
const p2 = new myPromise((resolve, reject) => {
setTimeout(() => {
reject(200)
}, 75)
})
const p3 = new myPromise((resolve, reject) => {
setTimeout(() => {
reject(300)
}, 150)
})
const pArr = myPromise.allSettled([p1, p2, p3])
setTimeout(() => {
console.log(pArr);
}, 1000)
console.log(pArr);
// p1.then(
// (value) => {
// console.log(`成功1 ${value}`);
// },
// (reason) => {
// console.log(`失败1 ${reason}`);
// }
// );
// p1.then(
// (value) => {
// console.log(`成功2 ${value}`);
// },
// (reason) => {
// console.log(`失败2 ${reason}`);
// }
// );
// p1.then(
// (value) => {
// console.log(`成功3 ${value}`);
// },
// (reason) => {
// console.log(`失败3 ${reason}`);
// }
// );
// p1.then(
// (value) => {
// console.log(`成功4 ${value}`);
// },
// (reason) => {
// console.log(`失败4 ${reason}`);
// }
// );
// console.log(p1);
// setTimeout(() => {
// console.log(p1);
// }, 4000)
// 2. 定义myPromise(),其得到一个函数,执行这个函数
function myPromise(executor) {
// 准备部分:
// 3.初始化
this.PromiseResult = undefined;
this.PromiseState = "pending";
// 4. 保存this
let _this = this;
// 12. 保存之前pending状态的执行函数
// 13. 兼容多个p1.then()方法,把待执行函数从{}变成数组
this.previousCallbackFn = [];
// 4.在myPromise里面,executor是() => {}这个函数,他接受两个参数,resolve, reject,实际上他们也是函数,所以需要定义和引用
function resolve(value) {
console.log(`hello, this is resolve, get a value: ${value}`);
_this.PromiseResult = value;
_this.PromiseState = "fulfilled";
}
// 5.如果用箭头函数定义,就可以不用this绑定
const resolveArrowFn = (value) => {
// 6.状态只能改变一次
if (this.PromiseState !== "pending") return;
// console.log(`hello, this is resolve, get a value: ${value}`);
this.PromiseResult = value;
this.PromiseState = "fulfilled";
// // 12.2 异步执行的函数在这里执行,如果是pending,那么执行这个语句
// this.previousCallbackFn.onfulfilled
// ? this.previousCallbackFn.onfulfilled()
// : "";
// 13. 兼容多个p1.then() 方法(p1.then()的多次调用)
this.previousCallbackFn.forEach(item => item.onfulfilled())
};
function reject(reason) {
console.log(`oh no, this is reject, get a reason: ${reason}`);
_this.PromiseResult = reason;
_this.PromiseState = "rejected";
}
const rejectArrowFn = (reason) => {
// 6.状态只能改变一次
if (this.PromiseState !== "pending") return;
// console.log(`oh no, this is reject, get a reason: ${reason}`);
this.PromiseResult = reason;
this.PromiseState = "rejected";
// // 12.2 异步执行的函数在这里执行,如果是pending,那么执行这个语句
// this.previousCallbackFn.onrejected
// ? this.previousCallbackFn.onrejected()
// : "";
// 13. 兼容多个p1.then() 方法(p1.then()的多次调用)
this.previousCallbackFn.forEach(item => item.onrejected())
};
// 7.then方法,放到promise.prototype.then()上
// 11.当onfulfilled, onrejected没有传递函数来使用时,规定默认的函数,onfulfilled就是resolve(value),onrejected就是抛出错误
//? 13.这里非常奇怪,只能用Object.assign合并对象,不能直接为myPromise.prototype添加then方法
//! 13 问题已解决,因为之前用的是箭头函数,this指向混乱
myPromise.prototype.then = function (onfulfilled = value => value, onrejected = reason => {throw reason}){
// console.log(`实例化对象的状态是${this.PromiseState}`);
// 9.then()方法对应几种情况:
/**
* then()方法返回一个新的promise实例
* 1.返回一个值:p 以该返回值作为其兑现值。
* 2.没有返回任何值:p 以 undefined 作为其兑现值。
* 3.抛出一个错误:p 抛出的错误作为其拒绝值。
* 4.返回一个已兑现的 Promise 对象:p 以该 Promise 的值作为其兑现值。
* 5.返回一个已拒绝的 Promise 对象:p 以该 Promise 的值作为其拒绝值。
* 6.返回另一个待定的 Promise 对象:p 保持待定状态,并在该 Promise 对象被兑现/拒绝后立即以该 Promise 的值作为其兑现/拒绝值。
*/
return new myPromise((resolve, reject) => {
// 10. 公共部分封装成函数
const _commenFn = (callback) => {
setTimeout(() => {
try {
const value = callback(this.PromiseResult);
if (value instanceof myPromise) {
value.then(resolve, reject);
} else {
resolve(value);
}
} catch (error) {
reject(error);
}
});
};
if (this.PromiseState === "fulfilled") {
// 8.不要立即执行,放到定时器里,可以在本轮事件循环的末尾执行
_commenFn.call(this, onfulfilled);
} else if (this.PromiseState === "rejected") {
// 8.不要立即执行,放到定时器里,可以在本轮事件循环的末尾执行
_commenFn.call(this, onrejected);
} else {
// 12.当promise中的代码也是异步时,this.PromiseState暂时为pending,
// 上面的立即执行会失效,我们要等到状态变更为上述两个时再执行
// console.log(`完蛋了,你想立即执行,可是我现在的状态是${this.PromiseState},执行了一个寂寞`);
// 12.1 如果你想使用while等待,你会发现其实这里没有人处理这个状态,出现死循环
// while(this.PromiseState === 'pending') {
// console.log('1');
// }
// if (this.PromiseState === "fulfilled") {
// // 8.不要立即执行,放到定时器里,可以在本轮事件循环的末尾执行
// _commenFn(onfulfilled)
// }
// else if (this.PromiseState === "rejected") {
// // 8.不要立即执行,放到定时器里,可以在本轮事件循环的末尾执行
// _commenFn(onrejected)
// }
// 那么一种方法,可以出现这种情况时,把要执行的函数挂载到自己身上,重复调用自己,等待自己状态出现后,再执行原先的函数
// 这种方法不能处理有多个p1.then的情况,previousCallbackFn应该兼容多个
// // 不兼容 START
// this.previousCallbackFn = {
// onfulfilled: _commenFn.bind(this, onfulfilled),
// onrejected: _commenFn.bind(this, onrejected),
// };
// // 不兼容 END
// 兼容 START
this.previousCallbackFn.push({
onfulfilled: _commenFn.bind(this, onfulfilled),
onrejected: _commenFn.bind(this, onrejected)
})
// 兼容 END
}
});
}
// 14 promise.catch方法
myPromise.prototype.catch = function(onrejected) {
return this.then(undefined, onrejected)
}
// 执行部分
// 5. 在执行时,executor可能会发生错误,捕获异常信息使用trycatch
try {
executor(resolveArrowFn, rejectArrowFn);
} catch (error) {
_this.PromiseResult = typeof error === "object" ? error.message : error;
_this.PromiseState = "rejected";
}
}
// // 3. 如果在外部环境定义,为了不污染全局变量window,用这种方式:
// (function(window) {
// function myPromiseExample(executor) {
// executor()
// }
// window.myPromiseExample = myPromiseExample
// })(window)ES6只用class的解决方案
// promise-es6.js
(function (window) {
class Promise {
constructor(executor) {
// 初始化状态
this.PromiseState = "pending";
this.PromiseResult = undefined;
// 回调函数的数组
this.callbackFn = []
// 使用箭头函数定义,this绑定在Promise里面
const resolve = (value) => {
// 状态只能改变一次
if (this.PromiseState !== "pending") return;
this.PromiseResult = value;
this.PromiseState = "fulfilled";
this.callbackFn.forEach(item => item.onfulfilled())
};
const reject = (reason) => {
// 状态只能改变一次
if (this.PromiseState !== "pending") return;
this.PromiseResult = reason;
this.PromiseState = "rejected";
this.callbackFn.forEach(item => item.onrejected())
};
// 调用执行器函数
try {
executor(resolve, reject);
} catch (error) {
this.PromiseResult = typeof error === "object" ? error.message : error;
this.PromiseState = "rejected";
}
}
// 在原型上添加then方法
then(onfulfilled = value => value, onrejected = reason => {throw reason}) {
return new Promise((resolve, reject) => {
// 封装公共函数
const _commenFn = (callback) => {
setTimeout(() => {
// 获取不同回调函数的结果
try {
const value = callback(this.PromiseResult)
if (value instanceof Promise) {
value.then(resolve, reject)
} else {
resolve(value)
}
} catch (error) {
reject(error)
}
})
};
if (this.PromiseState === 'fulfilled') {
_commenFn(onfulfilled)
} else if(this.PromiseState === 'rejected') {
_commenFn(onrejected)
} else {
// 订阅
this.callbackFn.push({
onfulfilled: () => _commenFn(onfulfilled),
onrejected: () => _commenFn(onrejected)
})
}
})
}
// 在原型上添加catch方法
catch(onrejected) {
return this.then(undefined, onrejected)
}
// 在原型上添加finally方法
finally(callback) {
return this.then(
value => Promise.resolve(callback()).then(() => value),
reason => Promise.resolve(callback()).then(() => { throw reason })
)
}
// 在类上添加resolve方法
static resolve = function(value) {
if (value instanceof Promise) {
return value
} else {
return new Promise(resolve => {
resolve(value)
})
}
}
// 在类上添加reject方法
static reject = function(value) {
return new Promise((resolve, reject) => {
reject(value)
})
}
// 在类上添加all方法
static all = function(promiseArr) {
let result = []
let count = 0
return new Promise((resolve, reject) => {
promiseArr.forEach((item, index) => {
// item有可能是普通值
Promise.resolve(item).then(value => {
result[index] = value
count++
// 在这里判断退出条件
if (count === promiseArr.length) {
resolve(result)
}
}, reason => {
reject(reason)
})
})
})
}
// 在类上添加race方法
static race = function(promiseArr) {
let result = []
let count = 0
return new Promise((resolve, reject) => {
promiseArr.forEach((item, index) => {
Promise.resolve(item).then(value => {
resolve(value)
}, reason => {
reject(reason)
})
})
})
}
// 在类上添加allSettled方法
static allSettled = function(promiseArr) {
let result = []
let count = 0
return new Promise((resolve, reject) => {
promiseArr.forEach((item, index) => {
Promise.resolve(item).then(value => {
result[index] = {status: 'fulfilled', value}
count++
if (count === promiseArr.length) {
resolve(result)
}
}, reason => {
result[index] = {status: 'rejected', reason}
count++
if (count === promiseArr.length) {
resolve(result)
}
})
})
})
}
//! 在类上添加allSettled方法 调用all版本:
static allSettledByAll = function(promiseArr) {
let result = [];
let count = 0;
// 使用 Promise.all 来等待所有 Promise 执行完成
return Promise.all(promiseArr.map((item, index) => {
// 对每个 Promise 对象进行处理,并返回一个新的 Promise
return Promise.resolve(item).then(
// 当 Promise 被 resolved 时,将结果存入 result 中
value => {
result[index] = { status: 'fulfilled', value };
},
// 当 Promise 被 rejected 时,将错误信息存入 result 中
reason => {
result[index] = { status: 'rejected', reason };
}
);
})).then(() => {
// 在所有 Promise 执行完成后,将结果返回
return result;
});
};
// any方法
static any = function(promiseArr) {
let errors = []
let count = 0
return new Promise((resolve, reject) => {
promiseArr.forEach((item, index) => {
Promise.resolve(item).then(value => {
resolve(value)
}, reason => {
errors[index] = reason
count++
if (count === promiseArr.length) {
let myAggr = new AggregateError(errors, 'All promises were rejected');
myAggr.stack = myAggr.stack.replace(/\n.*/g, '');
reject(myAggr);
}
})
})
})
}
}
window.Promise = Promise;
})(window);Bug解决 \ 经验总结
finally的手写
finally本质上是then方法的特例。
promise
.finally(() => {
// 语句
});
// 等同于
promise
.then(
result => {
// 语句
return result;
},
error => {
// 语句
throw error;
}
);上面代码中,如果不使用finally方法,同样的语句需要为成功和失败两种情况各写一次。有了finally方法,则只需要写一次。
它的实现也很简单。
Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};上面代码中,不管前面的 Promise 是fulfilled还是rejected,都会执行回调函数callback。
从上面的实现还可以看到,finally方法总是会返回原来的值。
// resolve 的值是 undefined
Promise.resolve(2).then(() => {}, () => {})
// resolve 的值是 2
Promise.resolve(2).finally(() => {})
// reject 的值是 undefined
Promise.reject(3).then(() => {}, () => {})
// reject 的值是 3
Promise.reject(3).finally(() => {})需要注意其他方法如catch方法会破坏原先的处理
const p5 = Promise.all([1, 2, 3, new Promise((resolve, reject) => {
setTimeout(() => {
reject(666)
}, 4000);
})]).catch(reason => {
console.log(reason);
return '现在我使用catch处理,原先的实例状态指向catch,状态应该是fulfilled'
});
console.log(p5);
