Open yanyue404 opened 2 years ago
手写 Promise 是面试的时候大家都逃避的送命题,在学些了解后发现通过实现源码更能将新一代的异步方案理解的通透,知其然知其所以然的运用。
如果直接将源码贴到此处势必不能有更大的收获,下面就按实现版本来看做简要分析。
Promise 是 CommonJS 提出来的这一种规范,有多个版本,在 ES6 当中已经纳入规范,原生支持 Promise 对象,非 ES6 环境可以用类似 Bluebird、Q 这类库来支持。
Promise 可以将回调变成链式调用写法,流程更加清晰,代码更加优雅,还可以批量处理异步任务。
简单归纳下 Promise:三个状态、两个过程、一个方法,快速记忆方法:3-2-1
三个状态:pending、fulfilled、rejected
两个过程:
一个方法:then
当然还有其他概念,如 catch、 Promise.all/race/allSettled。
基础测试用例
// 1. 链式调用 var p1 = new Promise(function (resolve, reject) { console.log("init Promise"); if (Math.random() > 0.5) { resolve("大"); } else { reject("小"); } }); p1.then( (data) => console.log("success", data), (reason) => console.log("error", reason) ).then( () => console.log("success 2"), () => console.log("error 2") ); // 2. 异步延时 var sleep = (time, data) => new Promise(function (resolve, reject) { setTimeout(resolve, time, data); }); sleep(3000, "时间到!").then((val) => { console.log(val); }); // 3. 状态变更后不可变 const p2 = new Promise(function (resolve, reject) { resolve("失败了!"); reject("还会成功吗!"); }); p2.then( (data) => console.log(data), (reason) => console.log(reason) ); // Promise 打印日志: // init Promise // success 大 / error 小 // 失败了! // success 2 / error 2 // 时间到!(延时 3 s)
Promise 的基本特征
手写基础版
class Promise { constructor(executor) { this.status = "pending"; this.handleFulfilled = []; // 存储成功后的回调 this.handleRejection = []; // 存储失败后的回调 // ! resolve 形参的实际参数在这儿 const resolve = (data) => { // 状态变更只有一次 if (this.status !== "pending") { return; } this.status = "fulfilled"; // ! 等一会,否则 handleFulfilled 为空 setTimeout(() => { this.handleFulfilled.forEach((fn) => fn(data)); }, 0); }; const reject = (reason) => { if (this.status !== "pending") { return; } this.status = "rejected"; setTimeout(() => { this.handleRejection.forEach((fn) => fn(reason)); }, 0); }; try { executor(resolve, reject); } catch (e) { // 遇到错误时,捕获错误,执行 reject 函数 reject(e); } } then(fulfilledFn, rejectedFn) { this.handleFulfilled.push(fulfilledFn); this.handleRejection.push(rejectedFn); return this; } }
测试用例:
// 简易版 Promise 打印日志: // init Promise // success 大 / error 小 // success 2 / error 2 (x 未通过) // 失败了! // 时间到!(延时 3 s)
存在的问题:
手写 Promise,需要遵守怎样的规则,业界所有 Promise 的类库都遵循 Promise/A+ 规范。译文
先按 Promise 的基本规范对上面的基础版进行改进。
executor
pending
fulfilled
rejected
value
undefined/thenable/promise
reason
onFulfilled
onRejected
const PENDING = "PENDING"; const FULFILLED = "FULFILLED"; const REJECTED = "REJECTED"; class Promise { constructor(executor) { this.status = PENDING; // 默认状态为 PENGING this.value = undefined; // 存放成功状态得值 this.reason = undefined; // 存放失败状态得值 this.handleFulfilled = []; // 存储成功后的回调 this.handleRejection = []; // 存储失败后的回调 // ! resolve 形参的实际参数在这儿 const resolve = (data) => { // 状态变更只有一次 if (this.status === PENDING) { this.status = FULFILLED; this.value = data; this.handleFulfilled.forEach((fn) => fn(data)); } }; const reject = (reason) => { if (this.status === PENDING) { this.status = REJECTED; this.reason = reason; this.handleRejection.forEach((fn) => fn(reason)); } }; try { executor(resolve, reject); } catch (e) { // 遇到错误时,捕获错误,执行 reject 函数 reject(e); } } then(onFulfilled, onRejected) { if (this.status === FULFILLED) { onFulfilled(this.value); } if (this.status === REJECTED) { onRejected(this.reason); } if (this.status === PENDING) { this.handleFulfilled.push(() => onFulfilled(this.value)); this.handleRejection.push(() => onRejected(this.reason)); } return this; } }
规范思路梳理
如果调用 then 时,promise 已经成功,则执行 onFulfilled,并将 promise 的值作为参数传递进去。 如果 promise 已经失败,那么执行 onRejected, 并将 promise 失败的原因作为参数传递进去。如果 promise 的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行(发布订阅)
then
源码实现
const PENDING = "PENDING"; const FULFILLED = "FULFILLED"; const REJECTED = "REJECTED"; // 将 onFufilled 的返回值进行判断取值处理,把最后获得的普通值放入最外面那层的 Promise 的 resolve 函数中 const resolvePromise = (promise2, x, resolve, reject) => { // 自己等待自己完成是错误的实现,用一个循环引用的类型错误,结束掉 promise Promise/A+ 2.3.1 if (promise2 === x) { return reject( new TypeError("Chaining cycle detected for promise #<Promise>") ); } // 只能调用一次,为了判断resolve过的就不用再reject了,(比如有reject和resolve的时候)Promise/A+ 2.3.3.3.3 let called; // 如果 x 不是null,是对象或者方法 if ((typeof x === "object" && x != null) || typeof x === "function") { try { // 这个首先存储对 x.then 的引用,然后测试该引用 let then = x.then; if (typeof then === "function") { // 那我们就认为他是promise,call他,因为then方法中的this来自自己的promise对象 // 不要写成 x.then,直接 then.call 就可以了 因为 x.then 会再次取值,Object.defineProperty Promise/A+ 2.3.3.3 // 第一个参数是将x这个promise方法作为this指向,后两个参数分别为成功失败回调 then.call( x, (y) => { // 根据 promise 的状态决定是成功还是失败 if (called) return; called = true; // 递归解析的过程(因为可能 promise 中还有 promise) Promise/A+ 2.3.3.3.1 resolvePromise(promise2, y, resolve, reject); }, (r) => { // 只要失败就失败 Promise/A+ 2.3.3.3.2 if (called) return; called = true; reject(r); } ); } else { // 如果 x.then 是个普通值就直接返回 resolve 作为结果 Promise/A+ 2.3.3.4 resolve(x); } } catch (e) { // Promise/A+ 2.3.3.2 if (called) return; called = true; reject(e); } } else { // 如果 x 是个普通值就直接返回 resolve 作为结果 Promise/A+ 2.3.4 resolve(x); } }; class Promise { constructor(executor) { this.status = PENDING; this.value = undefined; this.reason = undefined; this.onResolvedCallbacks = []; this.onRejectedCallbacks = []; let resolve = (value) => { if (this.status === PENDING) { this.status = FULFILLED; this.value = value; this.onResolvedCallbacks.forEach((fn) => fn()); } }; let reject = (reason) => { if (this.status === PENDING) { this.status = REJECTED; this.reason = reason; this.onRejectedCallbacks.forEach((fn) => fn()); } }; try { executor(resolve, reject); } catch (error) { reject(error); } } then(onFulfilled, onRejected) { //解决 onFufilled,onRejected 没有传值的问题 //Promise/A+ 2.2.1 / Promise/A+ 2.2.5 / Promise/A+ 2.2.7.3 / Promise/A+ 2.2.7.4 onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) => v; //因为错误的值要让后面访问到,所以这里也要抛出个错误,不然会在之后 then 的 resolve 中捕获 onRejected = typeof onRejected === "function" ? onRejected : (err) => { throw err; }; // 每次调用 then 都返回一个新的 promise Promise/A+ 2.2.7 let promise2 = new Promise((resolve, reject) => { if (this.status === FULFILLED) { //Promise/A+ 2.2.2 //Promise/A+ 2.2.4 --- setTimeout 宏任务模拟异步 setTimeout(() => { try { //Promise/A+ 2.2.7.1 // 因为有的时候需要判断then中的方法是否返回一个promise对象,所以需要判断 // 如果返回值为promise对象,则需要取出结果当作promise2的resolve结果 // 如果不是,直接作为promise2的resolve结果 let x = onFulfilled(this.value); // x可能是一个proimise // 抽离出一个公共方法来判断他们是否为promise对象 resolvePromise(promise2, x, resolve, reject); } catch (e) { //Promise/A+ 2.2.7.2 reject(e); } }, 0); } if (this.status === REJECTED) { //Promise/A+ 2.2.3 setTimeout(() => { try { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }, 0); } if (this.status === PENDING) { this.onResolvedCallbacks.push(() => { setTimeout(() => { try { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }, 0); }); this.onRejectedCallbacks.push(() => { setTimeout(() => { try { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }, 0); }); } }); return promise2; } }
测试一下,打印日志也对了:
// Promise 打印日志: // init Promise // error 小 // 失败了! // success 2 // 时间到!(延时 3 s)
再试试 then 的链式调用和值的穿透:
const promise = new Promise((resolve, reject) => { reject("失败"); }) .then() .then() .then( (data) => { console.log(data); }, (err) => { console.log("[Error]:", err); //log: [Error]: 失败 } );
虽然上述的 promise 源码已经符合 Promise/A+ 的规范,但是原生的 Promise 还提供了一些其他方法,如:
Promise.prototype.catch()
Promise.prototype.finally()
Promise.resolve(value)
Promise.reject(error)
Promise.all(promises)
Promise.race(promises)
Promise.any(promises)
Promise.allSettled(promises)
下面具体说一下每个方法的实现:
Promise.prototype.catch
先从错误捕获开始,catch 用来捕获 promise 的异常,就相当于一个没有成功的 then。
Promise.prototype.catch = function (errCallback) { return this.then(undefined, errCallback); };
测试例子:
// 抛出一个错误,大多数时候将调用catch方法 var p1 = new Promise(function (resolve, reject) { throw "Uh-oh!"; }); p1.catch(function (e) { console.log(e); // "Uh-oh!" }); // 在异步函数中抛出的错误不会被catch捕获到 var p2 = new Promise(function (resolve, reject) { setTimeout(function () { throw "Uncaught Exception!"; }, 1000); }); p2.catch(function (e) { console.log(e); // 不会执行 });
finally 方法,在 promise 结束时,无论结果是 fulfilled 或者是 rejected,都会执行指定的回调函数。这为在 Promise 是否成功完成后都需要执行的代码提供了一种方式。 这避免了同样的语句需要在 then()和 catch()中各写一次的情况。
Promise.prototype.finally = function (callback) { return this.then( (value) => { return Promise.resolve(callback(value)).then(() => value); }, (reason) => { return Promise.resolve(callback(reason)).then(() => { throw reason; }); } ); };
const promise1 = Promise.resolve(123); promise1 .then((value) => { return value; }) .finally((res) => { console.log("finally", res); // finally 123 }); Promise.resolve(456) .finally(() => { return new Promise((resolve, reject) => { setTimeout(() => { resolve(123); }, 3000); }); }) .then((data) => { console.log(data, "success"); // 3秒后,456 'success' }) .catch((err) => { console.log(err, "error"); });
Promise.resolve
默认产生一个成功的 promise。Promise.resolve(value)方法返回一个以给定值解析后的 Promise 对象。如果这个值是一个 promise ,那么将返回这个 promise ;如果这个值是 thenable(即带有"then" 方法),返回的 promise 会“跟随”这个 thenable 的对象,采用它的最终状态;否则返回的 promise 将以此值完成。此函数将类 promise 对象的多层嵌套展平。
static resolve(data){ return new Promise((resolve,reject)=>{ resolve(data); }) }
如果参数是 promise 会等待这个 promise 解析完毕,在向下执行,所以这里需要在 constructor 方法中做一个小小的处理:
let reject = (reason) => { if (this.status === PENDING) { this.status = REJECTED; this.reason = reason; this.onRejectedCallbacks.forEach((fn) => fn()); } }; let resolve = (value) => { // 如果 value 是一个promise,那我们的库中应该也要实现一个递归解析 if (value instanceof Promise) { // 递归解析 return value.then(resolve, reject); } if (this.status === PENDING) { this.status = FULFILLED; this.value = value; this.onResolvedCallbacks.forEach((fn) => fn()); } };
const promise1 = Promise.resolve(123); promise1.then((value) => { console.log(value); // expected output: 123 }); Promise.resolve( new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() > 0.5) { resolve("ok"); } else { reject("err"); } }, 3000); }) ) .then((data) => { console.log(data, "success"); // ok success }) .catch((err) => { console.log(err, "error"); // err error });
Promise.reject()
默认产生一个失败的 promise,Promise.reject 是直接将值变成错误结果。
static reject(reason){ return new Promise((resolve,reject)=>{ reject(reason); }) }
Promise.all()
promise.all 是解决并发问题的,多个异步并发获取最终的结果(如果有一个失败则失败)。
Promise.all = function (values) { if (!Array.isArray(values)) { const type = typeof values; return new TypeError(`TypeError: ${type} ${values} is not iterable`); } return new Promise((resolve, reject) => { let resultArr = []; let orderIndex = 0; const processResultByKey = (value, index) => { resultArr[index] = value; if (++orderIndex === values.length) { resolve(resultArr); } }; for (let i = 0; i < values.length; i++) { let value = values[i]; if (value && typeof value.then === "function") { value.then((value) => { processResultByKey(value, i); }, reject); } else { processResultByKey(value, i); } } }); };
测试一下:
Promise.all([ new Promise((resolve) => setTimeout(() => resolve(1), 3000)), // 1 new Promise((resolve) => setTimeout(() => resolve(2), 2000)), // 2 new Promise((resolve) => setTimeout(() => resolve(3), 1000)), // 3 ]).then(alert); // 1,2,3 当上面这些 promise 准备好时:每个 promise 都贡献了数组中的一个元素 Promise.all([ new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)), new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 2000) ), new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000)), ]).catch(alert); // Error: Whoops!
Promise.race()
Promise.race 用来处理多个请求,采用最快的(谁先完成用谁的)。
Promise.race = function (promises) { return new Promise((resolve, reject) => { // 一起执行就是for循环 for (let i = 0; i < promises.length; i++) { let val = promises[i]; if (val && typeof val.then === "function") { val.then(resolve, reject); } else { // 普通值 resolve(val); } } }); };
这里第一个 promise 最快,所以它变成了结果。第一个 settled 的 promise “赢得了比赛”之后,所有进一步的 result/error 都会被忽略。
例如,这里的结果将是 1:
Promise.race([ new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)), new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 2000) ), new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000)), ]).then(alert); // 1
Promise.any()
与 Promise.race 类似,区别在于 Promise.any 只等待第一个 fulfilled 的 promise,并将这个 fulfilled 的 promise 返回,它不会等待其他的 promise 全部完成。如果给出的 promise 都 rejected,那么则返回 rejected 的 promise 和 AggregateError 错误类型的 error 实例—— 一个特殊的 error 对象,在其 errors 属性中存储着所有 promise error。
Promise.any([ new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 1000) ), new Promise((resolve, reject) => setTimeout(() => resolve(1), 2000)), new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000)), ]).then(alert); // 1
这里的第一个 promise 是最快的,但 rejected 了,所以第二个 promise 则成为了结果。在第一个 fulfilled 的 promise “赢得比赛”后,所有进一步的结果都将被忽略。
这是一个所有 promise 都失败的例子:
Promise.any([ new Promise((resolve, reject) => setTimeout(() => reject(new Error("Ouch!")), 1000) ), new Promise((resolve, reject) => setTimeout(() => reject(new Error("Error!")), 2000) ), ]).catch((error) => { console.log(error.constructor.name); // AggregateError console.log(error.errors[0]); // Error: Ouch! console.log(error.errors[1]); // Error: Error! });
正如你所看到的,我们在 AggregateError 错误类型的 error 实例的 errors 属性中可以访问到失败的 promise 的 error 对象。
实现该方法,可以通过上面的两个例子:
Promise.any 只要传入的 promise 有一个是 fullfilled 则立即 resolve 出去,否则将所有 reject 结果收集起来并返回 AggregateError
Promise.any = function (promises) { return new Promise((resolve, reject) => { promises = Array.isArray(promises) ? promises : []; let len = promises.length; // 用于收集所有 reject let errs = []; // 如果传入的是一个空数组,那么就直接返回 AggregateError if (len === 0) return reject(new AggregateError("All promises were rejected")); promises.forEach((promise) => { promise.then( (value) => { resolve(value); }, (err) => { len--; errs.push(err); if (len === 0) { reject(new AggregateError(errs)); } } ); }); }); };
Promise.allSettled()
如果任意的 promise reject,则 Promise.all 整个将会 reject。当我们需要 所有 结果都成功时,它对这种“全有或全无”的情况很有用:Promise.allSettled 等待所有的 promise 都被 settle,无论结果如何。结果数组具有:
Promise.allSettled = function (promises) { const rejectHandler = (reason) => ({ status: "rejected", reason }); const resolveHandler = (value) => ({ status: "fulfilled", value }); const convertedPromises = promises.map((p) => Promise.resolve(p).then(resolveHandler, rejectHandler) ); return Promise.all(convertedPromises); };
Promise.allSettled([ new Promise((resolve) => setTimeout(() => resolve(1), 3000)), // 1 new Promise((resolve) => setTimeout(() => resolve(2), 2000)), // 2 new Promise((resolve) => setTimeout(() => resolve(3), 1000)), // 3 ]).then(console.log); // [{status: 'fulfilled', value: 1}, {status: 'fulfilled', value: 2}, {status: 'fulfilled', value: 3}] Promise.allSettled([ new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)), new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 2000) ), new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000)), ]).then(console.log); // [{status: 'fulfilled', value: 1}, {status: 'rejected', value: "Error: Whoops!"}, {status: 'fulfilled', value: 3}]测试一下:
前言
手写 Promise 是面试的时候大家都逃避的送命题,在学些了解后发现通过实现源码更能将新一代的异步方案理解的通透,知其然知其所以然的运用。
如果直接将源码贴到此处势必不能有更大的收获,下面就按实现版本来看做简要分析。
回顾 Promise
Promise 是 CommonJS 提出来的这一种规范,有多个版本,在 ES6 当中已经纳入规范,原生支持 Promise 对象,非 ES6 环境可以用类似 Bluebird、Q 这类库来支持。
Promise 可以将回调变成链式调用写法,流程更加清晰,代码更加优雅,还可以批量处理异步任务。
简单归纳下 Promise:三个状态、两个过程、一个方法,快速记忆方法:3-2-1
三个状态:pending、fulfilled、rejected
两个过程:
一个方法:then
当然还有其他概念,如 catch、 Promise.all/race/allSettled。
基础版
基础测试用例
Promise 的基本特征
手写基础版
测试用例:
存在的问题:
认识 Promise /A+ 规范
手写 Promise,需要遵守怎样的规则,业界所有 Promise 的类库都遵循 Promise/A+ 规范。译文
改进版
先按 Promise 的基本规范对上面的基础版进行改进。
executor
,executor
接受两个参数,分别是 resolve 和 reject;pending
,fulfilled
,orrejected
, 默认状态是pending
,只能从pending
到rejected
, 或者从pending
到fulfilled
,状态一旦确认,就不会再改变;「规范 Promise/A+ 2.1」value
保存成功状态的值,可以是undefined/thenable/promise
;「规范 Promise/A+ 1.3」reason
保存失败状态的值;「规范 Promise/A+ 1.5」onFulfilled
,参数是 promise 的value
;onRejected
, 参数是 promise 的reason
;Promise A+规范版
规范思路梳理
如果调用 then 时,promise 已经成功,则执行 onFulfilled,并将 promise 的值作为参数传递进去。 如果 promise 已经失败,那么执行 onRejected, 并将 promise 失败的原因作为参数传递进去。如果 promise 的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行(发布订阅)
onFulfilled
和onRejected
可以缺省,如果onFulfilled
或者onRejected
不是函数,将其忽略,且依旧可以在下面的then
中获取到之前返回的值;「规范 Promise/A+ 2.2.1、2.2.1.1、2.2.1.2」源码实现
测试一下,打印日志也对了:
再试试 then 的链式调用和值的穿透:
完善 Promise API
虽然上述的 promise 源码已经符合 Promise/A+ 的规范,但是原生的 Promise 还提供了一些其他方法,如:
Promise.prototype.catch()
Promise.prototype.finally()
Promise.resolve(value)
—— 使用给定 value 创建一个 resolved 的 promise。Promise.reject(error)
—— 使用给定 error 创建一个 rejected 的 promise。Promise.all(promises)
—— 等待所有 promise 都 resolve 时,返回存放它们结果的数组。如果给定的任意一个 promise 为 reject,那么它就会变成 Promise.all 的 error,所有其他 promise 的结果都会被忽略。Promise.race(promises)
—— 等待第一个 settle 的 promise,并将其 result/error 作为结果返回。Promise.any(promises)
(ES2021 新增方法)—— 等待第一个 fulfilled 的 promise,并将其结果作为结果返回。如果所有 promise 都 rejected,Promise.any 则会抛出 AggregateError 错误类型的 error 实例。Promise.allSettled(promises)
(ES2020 新增方法)—— 等待所有 promise 都 settle 时,并以包含以下内容的对象数组的形式返回它们的结果:下面具体说一下每个方法的实现:
Promise.prototype.catch
先从错误捕获开始,catch 用来捕获 promise 的异常,就相当于一个没有成功的 then。
测试例子:
Promise.prototype.finally()
finally 方法,在 promise 结束时,无论结果是 fulfilled 或者是 rejected,都会执行指定的回调函数。这为在 Promise 是否成功完成后都需要执行的代码提供了一种方式。 这避免了同样的语句需要在 then()和 catch()中各写一次的情况。
测试用例:
Promise.resolve
默认产生一个成功的 promise。Promise.resolve(value)方法返回一个以给定值解析后的 Promise 对象。如果这个值是一个 promise ,那么将返回这个 promise ;如果这个值是 thenable(即带有"then" 方法),返回的 promise 会“跟随”这个 thenable 的对象,采用它的最终状态;否则返回的 promise 将以此值完成。此函数将类 promise 对象的多层嵌套展平。
如果参数是 promise 会等待这个 promise 解析完毕,在向下执行,所以这里需要在 constructor 方法中做一个小小的处理:
测试例子:
Promise.reject()
默认产生一个失败的 promise,Promise.reject 是直接将值变成错误结果。
Promise.all()
promise.all 是解决并发问题的,多个异步并发获取最终的结果(如果有一个失败则失败)。
测试一下:
Promise.race()
Promise.race 用来处理多个请求,采用最快的(谁先完成用谁的)。
这里第一个 promise 最快,所以它变成了结果。第一个 settled 的 promise “赢得了比赛”之后,所有进一步的 result/error 都会被忽略。
例如,这里的结果将是 1:
Promise.any()
与 Promise.race 类似,区别在于 Promise.any 只等待第一个 fulfilled 的 promise,并将这个 fulfilled 的 promise 返回,它不会等待其他的 promise 全部完成。如果给出的 promise 都 rejected,那么则返回 rejected 的 promise 和 AggregateError 错误类型的 error 实例—— 一个特殊的 error 对象,在其 errors 属性中存储着所有 promise error。
例如,这里的结果将是 1:
这里的第一个 promise 是最快的,但 rejected 了,所以第二个 promise 则成为了结果。在第一个 fulfilled 的 promise “赢得比赛”后,所有进一步的结果都将被忽略。
这是一个所有 promise 都失败的例子:
正如你所看到的,我们在 AggregateError 错误类型的 error 实例的 errors 属性中可以访问到失败的 promise 的 error 对象。
实现该方法,可以通过上面的两个例子:
Promise.any 只要传入的 promise 有一个是 fullfilled 则立即 resolve 出去,否则将所有 reject 结果收集起来并返回 AggregateError
Promise.allSettled()
如果任意的 promise reject,则 Promise.all 整个将会 reject。当我们需要 所有 结果都成功时,它对这种“全有或全无”的情况很有用:Promise.allSettled 等待所有的 promise 都被 settle,无论结果如何。结果数组具有:
测试一下:
参考文章