js基础之Promise(全面+手写实现)
1. 是什么
Promise是一种异步编程的解决方案,用于处理异步操作并返回结果。
主要作用是解决回调函数嵌套(回调地狱)的问题,使异步操作更加清晰、易于理解和维护。
2. 怎么用
Promise有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。当一个Promise被创建时,它的状态为pending。当异步操作完成并成功时,Promise的状态会变为fulfilled,并返回一个结果。当异步操作失败时,Promise的状态会变为rejected,并返回一个错误信息。
基本语法
// 创建一个promise
let promise = new Promise(function(resolve, reject) {
// 异步操作
if (异步操作成功) {
resolve(value); // 将异步操作的结果传递给Promise对象,状态变为fulfilled
} else {
reject(error); // 将异步操作的错误信息传递给Promise对象,状态变为rejected
}
});
promise.then(function(result) {
// 异步操作成功时的处理代码
}).catch(function(error) {
// 异步操作失败时的处理代码
});
常用方法
-
then
then中一般传入两个参数(函数),第一个对应resolve成功的回调,第二个对应reject失败的回调,如下function onResolved(res) { console.log("resolved-" + res); // resolved-成功了 } function onRejected(err) { console.log("rejected-" + err); // rejected-失败了 } new Promise((resolve, reject) => { resolve('成功了'); // reject('失败了') }).then(onResolved, onRejected);
then的第二个参数就等同于catch方法,但是需要注意
- Promise内部报错,reject抛出错误后,then的第二个参数和catch方法都存在的情况下,只有then的第二个参数能捕获到,如果then的第二个参数不存在,catch方法会捕捉到
- catch不仅捕捉promise中抛出的错误,还会捕捉前面then中的错误
-
catch
捕捉promise错误函数,和then的第二个参数(函数)作用一样,处理错误,由于Promise抛出错误具有冒泡性质,能够不断传递,会传到catch中,所以一般来说所有错误处理放在catch中,then中只处理成功的,同时catch还会捕捉then中第一个参数(函数)抛出的异常new Promise((resolve, reject) => { reject(); }).catch((err)=> { console.log(err) });
-
finally
finally 方法没有参数,也不会改变 Promise 的状态,它只是在 Promise 结束时提供了一个通知机制,让我们可以在 Promise 结束后执行一些清理工作(比如操作文件的时候关闭文件流)。function onFinally() { console.log('结束'); } new Promise((resolve, reject) => {}).finally(onFinally);
-
all
接受一个具有Iterable接口的类型,如数组,Map,Set,传入多个promise,
每一个promise执行成功resolve,最后才执行成功(返回一个Promise实例),进入then,否则失败进入catchfunction p1() { var promise1 = new Promise(function (resolve, reject) { console.log("p1的第一条输出语句"); resolve("p1完成"); }); return promise1; } function p2() { var promise2 = new Promise(function (resolve, reject) { console.log("p2的第一条输出语句"); setTimeout(() => { console.log("p2的第二条输出语句"); resolve("p2完成"); }, 2000); }); return promise2; } function p3() { var promise3 = new Promise(function (resolve, reject) { console.log("p3的第一条输出语句"); resolve("p3完成"); }); return promise3; } Promise.all([p1(), p2(), p3()]).then(function (data) { console.log(data); }); // 输出 // p1的第一条输出语句; // p2的第一条输出语句; // p3的第一条输出语句; // p2的第二条输出语句[("p1完成", "p2完成", "p3完成")]; var p1 = new Promise((resolve, reject) => { setTimeout(resolve, 1000, 'one'); }); var p2 = new Promise((resolve, reject) => { setTimeout(resolve, 2000, 'two'); }); var p3 = new Promise((resolve, reject) => { setTimeout(resolve, 3000, 'three'); }); var p4 = new Promise((resolve, reject) => { setTimeout(resolve, 4000, 'four'); }); var p5 = new Promise((resolve, reject) => { reject('reject'); // setTimeout(resolve, 5000, 'five'); }); Promise.all([p1, p2, p3, p4, p5]).then(values => { console.log(values); // [ 'one', 'two', 'three', 'four', 'five' ] }, reason => { console.log(reason) // reject });
-
allSettled
接受一个具有Iterable接口的类型,如数组,Map,Set,传入多个promise,
每个promise状态改变成fulfilled或者rejected之后返回,返回的是一个数组对象,对象中有状态status和每一项的返回结果valuePromise.allSettled([p1, p2, p3, p4, p5]).then(values => { console.log(values); }, reason => { console.log(reason) }); // [ // { status: 'fulfilled', value: 'one' }, // { status: 'fulfilled', value: 'two' }, // { status: 'fulfilled', value: 'three' }, // { status: 'fulfilled', value: 'four' }, // { status: 'rejected', reason: 'reject' } // ]
-
race
以快为准,数组中所有的promise对象,有一个先执行了何种状态,该对象就为何种状态,并执行相应函数
接受一个具有Iterable接口的类型,如数组,Map,Set,传入多个promise,
其中有一个promise返回了,不管是fulfilled或者rejected,直接返回这个promise的结果function p1() { var promise1 = new Promise(function (resolve, reject) { console.log("p1的第一条输出语句"); resolve("p1完成"); }); return promise1; } function p2() { var promise2 = new Promise(function (resolve, reject) { console.log("p2的第一条输出语句"); setTimeout(() => { console.log("p2的第二条输出语句"); resolve("p2完成"); }, 2000); }); return promise2; } function p3() { var promise3 = new Promise(function (resolve, reject) { console.log("p3的第一条输出语句"); resolve("p3完成"); }); return promise3; } Promise.race([p1(), p2(), p3()]).then(function (data) { console.log(data); }); // 输出 // p1的第一条输出语句 // p2的第一条输出语句 // p3的第一条输出语句 // p1完成
-
any
接受一个具有Iterable接口的类型,如数组,Map,Set,传入多个promise,
当传入的任何一个promise成功的时候,不管其他是否成功或者失败,会把成功的那个promise返回
如果传入的是一个空的数组(Map,Set),返回一个已失败状态的promise,如下
注意
Promise的以上方法都属于 微任务。当Promise状态变为已解决(resolved)或被拒绝(rejected)时,这些方法会产生微任务。这些微任务会在主线程空闲时按照顺序依次执行。
3. 有什么问题
- 首先,无法取消 Promise,一旦新建它就会立即执行,无法中途取消。
- 其次,如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。
- 第三,当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
4. 手写实现
手写实现有助于我们更好的理解Promise,开始吧!
我们使用Es6类的方式,构建一个Promise,更直观好理解
基本实现
-
先写出一个雏形,维护三种状态,并定义reslove、reject、和then方法
class MyPromise { static PENDING = "等待"; static FULFILLED = "成功"; static REJECTED = "失败"; constructor(func) { this.status = MyPromise.PENDING; // 定义状态 this.result = null; // 定义返回结果 func(this.reslove.bind(this), this.reject.bind(this)); // 执行传入的函数 } reslove(result) { this.status = MyPromise.FULFILLED; // 更改状态 this.result = result; } reject(result) { this.status = MyPromise.FULFILLED; // 更改状态 this.result = result; } then(onFULFILLED, onREJECTED) { if (this.status === MyPromise.FULFILLED) { // 执行成功后的回调 onFULFILLED() } if (this.status === MyPromise.REJECTED) { // 执行失败后的回调 onREJECTED() } } }
-
注意
当Promise中抛出错误时,会把promise的状态改为失败并且将错误设置为结果,如下
const p = new Promise((resolve,reject)=> { throw new Error('出错') }) p.then((res)=> { console.log(res) },(err)=> { console.log(err.message) // log: 出错 })
then中两个参数可以传入undefined
const p = new Promise((resolve,reject)=> { resolve('成功') }) p.then(undefined,(err)=> { console.log(err) })
完善一下上面的两个问题,代码如下
class MyPromise { static PENDING = "等待"; static FULFILLED = "成功"; static REJECTED = "失败"; constructor(func) { this.status = MyPromise.PENDING; // 定义状态 this.result = null; // 定义返回结果 // 当Promise中抛出错误时,会把promise的状态改为失败并且将错误设置为结果 try { func(this.reslove.bind(this), this.reject.bind(this)); // 执行传入的函数 } catch (err) { this.reject(err); } } reslove(result) { this.status = MyPromise.FULFILLED; // 更改状态 this.result = result; } reject(result) { this.status = MyPromise.FULFILLED; // 更改状态 this.result = result; } then(onFULFILLED, onREJECTED) { // then中两个参数可以传入undefined,做下处理 onFULFILLED = typeof onFULFILLED === "function" ? onFULFILLED : (value) => { value; }; onREJECTED = typeof onREJECTED === "function" ? onREJECTED : (reason) => { throw reason; }; if (this.status === MyPromise.FULFILLED) { // 执行成功后的回调 onFULFILLED(this.result); } if (this.status === MyPromise.REJECTED) { // 执行失败后的回调 onREJECTED(this.result); } } }
-
继续完善
我们先写一个真实promises,看一下下面代码的执行顺序console.log('第一步') const p = new Promise((resolve,reject)=> { console.log('第二步') setTimeout(() => { resolve('成功') console.log('第四步') }); }) p.then((res)=> { console.log(res) },(err)=> { console.log(err) }) console.log('第三步') // 依次输出如下: // 第一步 // 第二步 // 第三步 // 第四步 // 成功
可以看到,then里面的代码是最后执行的,then属于微任务,resolve和reject 属于在事件循环末尾执行的,因此完善一下实现代码
class MyPromise { static PENDING = "等待"; static FULFILLED = "成功"; static REJECTED = "失败"; constructor(func) { this.status = MyPromise.PENDING; // 定义状态 this.result = null; // 定义返回结果 this.resloveCallbacks = []; // 存放reslove回调函数的数组 this.rejectCallbacks = []; // 存放reject回调函数的数组 // 当Promise中抛出错误时,会把promise的状态改为失败并且将错误设置为结果 try { func(this.reslove.bind(this), this.reject.bind(this)); // 执行传入的函数 } catch (err) { this.reject(err); } } reslove(result) { // resolve是在事件循环末尾执行的,所以这里用setTimeout包裹一下 setTimeout(() => { this.status = MyPromise.FULFILLED; // 更改状态 this.result = result; // 遍历执行PENDING状态时保存的reslove回调函数 this.resloveCallbacks.forEach((callback) => { callback(result); }); }); } reject(result) { // reject同样用setTimeout包裹一下 setTimeout(() => { this.status = MyPromise.FULFILLED; // 更改状态 this.result = result; // 遍历执行PENDING状态时保存的reject回调函数 this.rejectCallbacks.forEach((callback) => { callback(result); }); }); } then(onFULFILLED, onREJECTED) { // then中两个参数可以传入undefined,做下处理 onFULFILLED = typeof onFULFILLED === "function" ? onFULFILLED : (value) => { value; }; onREJECTED = typeof onREJECTED === "function" ? onREJECTED : (reason) => { throw reason; }; if (this.status === MyPromise.PENDING) { // PENDING状态时 this.resloveCallbacks.push(onFULFILLED); this.rejectCallbacks.push(onREJECTED); } if (this.status === MyPromise.FULFILLED) { setTimeout(() => { // 执行成功后的回调 onFULFILLED(this.result); }) } if (this.status === MyPromise.REJECTED) { setTimeout(() => { // 执行失败后的回调 onREJECTED(this.result); }) } } }
OK,到此我们可以测试一下
console.log('第一步') const p = new MyPromise((resolve,reject)=> { console.log('第二步') setTimeout(() => { resolve('成功') console.log('第四步') }); }) p.then((res)=> { console.log(res) },(err)=> { console.log(err) }) console.log('第三步') // 第一步 // 第二步 // 第三步 // 第四步 // 成功
实现then
-
下面进入重头戏-----then的 链式调用
先看一下示例,如下const p = new Promise((resolve, reject) => { setTimeout(() => { resolve("成功"); }); }); p.then((res) => { console.log("第一次then", res); return '返回一个正常值' // return new Promise((resolve)=> { // setTimeout(() => { // resolve('返回一个promise') // }); // }) // throw "抛出一个异常" }).then( (res) => { console.log("第二次then", res); }, (err) => { console.log("第二次then", err); } ); // 第一次then 成功 // 第二次then 返回一个正常值 | 第二次then 返回一个promise |第二次then 抛出一个异常
如果 then 返回的是一个正常值,那么就会把这个结果(value)作为参数,传递给下一个 then 的成功的回调(onFULFILLED);
如果 then 中抛出了异常,那么就会把这个异常(reason)作为参数,传递给下一个 then 的失败的回调(onREJECTED);
如果 then 返回的是一个 promise 或者其他 thenable 对象,那么需要等这个 promise 执行完成,promise 如果成功,就走下一个 then 的成功回调;如果失败,就走下一个 then 的失败回调要实现上面功(链式调用),我们需要在then方法中,返回一个 promise
then(onFULFILLED, onREJECTED) { let newPromise = new MyPromise((resolve, reject) => { // then中两个参数可以传入undefined,做下处理 onFULFILLED = typeof onFULFILLED === "function" ? onFULFILLED : (value) => { value; }; onREJECTED = typeof onREJECTED === "function" ? onREJECTED : (reason) => { throw reason; }; if (this.status === MyPromise.PENDING) { // PENDING状态时 this.resloveCallbacks.push(() => { try { let nextResult = onFULFILLED(this.result); resolve(nextResult) } catch (err) { reject(err); } }); this.rejectCallbacks.push(() => { try { let nextResult = onREJECTED(this.result); resolve(nextResult) } catch (err) { reject(err); } }); } if (this.status === MyPromise.FULFILLED) { setTimeout(() => { try { // 执行成功后的回调 let nextResult = onFULFILLED(this.result); resolve(nextResult) } catch (err) { reject(err); } }); } if (this.status === MyPromise.REJECTED) { setTimeout(() => { try { // 执行失败后的回调 let nextResult = onREJECTED(this.result); resolve(nextResult) } catch (err) { reject(err); } }); } }); return newPromise; }
这时我们测试一下,已经能实现链式调用了
const p = new MyPromise((resolve, reject) => { setTimeout(() => { resolve("成功"); }); }); p.then((res) => { console.log("第一次then", res); return "返回一个正常值"; }).then( (res) => { console.log("第二次then", res); }, (err) => { console.log("第二次then", err); } ); // 第一次then 成功 // 第二次then 返回一个正常值
这样就完成了吗?并没有
上面我们的then执行回调的地方,我们获取到回调执行结果之后就直接resolve出去了,如下try { let nextResult = onFULFILLED(this.result); resolve(nextResult) } catch (err) { reject(err); }
对于我们上面例子,直接返回一个基本数据类型(“返回一个正常值”)是可以实现的,
但是回调执行返回的结果,还可能存在其他类型,比如返回一个函数或者返回一个promise,或者失败抛出一个错误等等,对于这些情况,我们也需要进行处理 -
完善then的链式调用-----处理then中返回
我们封装一个resolvePromise方法,用来处理不同情况then(onFULFILLED, onREJECTED) { let newPromise = new MyPromise((resolve, reject) => { // then中两个参数可以传入undefined,做下处理 onFULFILLED = typeof onFULFILLED === "function" ? onFULFILLED : (value) => { value; }; onREJECTED = typeof onREJECTED === "function" ? onREJECTED : (reason) => { throw reason; }; if (this.status === MyPromise.PENDING) { // PENDING状态时 this.resloveCallbacks.push(() => { try { let nextResult = onFULFILLED(this.result); resolvePromise(newPromise, nextResult, resolve, reject); } catch (err) { reject(err); } }); this.rejectCallbacks.push(() => { try { let nextResult = onREJECTED(this.result); resolvePromise(newPromise, nextResult, resolve, reject); } catch (err) { reject(err); } }); } if (this.status === MyPromise.FULFILLED) { setTimeout(() => { try { // 执行成功后的回调 let nextResult = onFULFILLED(this.result); resolvePromise(newPromise, nextResult, resolve, reject); } catch (err) { reject(err); } }); } if (this.status === MyPromise.REJECTED) { setTimeout(() => { try { // 执行失败后的回调 let nextResult = onREJECTED(this.result); resolvePromise(newPromise, nextResult, resolve, reject); } catch (err) { reject(err); } }); } }); return newPromise; }
根据promise规范,实现的resolvePromise
function resolvePromise(newPromise, x, resolve, reject) { if (x === newPromise) { // 因为x是回调的结果值,如果x指向newPromise即自己,那么会重新解析自己,导致循环调用 throw new TypeError("禁止循环调用"); } // 如果x是一个Promise,我们必须等它完成(失败或成功)后得到一个普通值时,才能继续执行。 // 那我们把要执行的任务放在x.then()的成功回调和失败回调里面即可 // 这就表示x完成后就会调用我们的代码。 // 但是对于成功的情况,我们还需要再考虑下,x.then成功回调函数的参数,我们称为y // 那y也可能是一个thenable对象或者promise // 所以如果成功时,执行resolvePromise(promise2, y, resolve, reject) // 并且传入resolve, reject,当解析到普通值时就resolve出去,反之继续解析 // 这样子用于保证最后resolve的结果一定是一个非promise类型的参数 if (x instanceof MyPromise) { x.then( (y) => { resolvePromise(newPromise, y, resolve, reject); }, (r) => reject(r) ); } // (x instanceof myPromise) 处理了promise的情况,但是很多时候交互的promise可能不是原生的 // 就像我们现在写的一个myPromise一样,这种有then方法的对象或函数我们称为thenable。 // 因此我们需要处理thenable。 else if ((typeof x === "object" || typeof x === "function") && x !== null) { // 暂存x这个对象或函数的then,x也可能没有then,那then就会得到一个undefined try { var then = x.then; } catch (e) { // 如果读取then的过程中出现异常则reject异常出去 return reject(e); } // 判断then是否函数且存在,如果函数且存在那这个就是合理的thenable,我们要尝试去解析 if (typeof then === "function") { // 状态只能更新一次使用一个called防止反复调用 // 因为成功和失败的回调只能执行其中之一 let called = false; try { then.call( x, (y) => { // called就是用于防止成功和失败被同时执行,因为这个是thenable,不是promise // 需要做限制如果newPromise已经成功或失败了,则不会再处理了 if (called) return; called = true; resolvePromise(newPromise, y, resolve, reject); }, (r) => { // called就是用于防止成功和失败被同时执行,因为这个是thenable,不是promise // 需要做限制如果newPromise已经成功或失败了,则不会再处理了 if (called) return; called = true; reject(r); } ); // 上面那一步等价于,即这里把thenable当作类似于promise的对象去执行then操作 // x.then( // (y) => { // if (called) return; // called = true; // resolvePromise(newPromise, y, resolve, reject); // }, // (r) => { // if (called) return; // called = true; // reject(r); // } // ) } catch (e) { // called就是用于防止成功和失败被同时执行,因为这个是thenable,不是promise // 需要做限制如果newPromise已经成功或失败了,则不会再处理了 if (called) return; called = true; reject(e); } } else { // 如果是对象或函数但不是thenable(即没有正确的then属性) // 当成普通值则直接resolve出去 resolve(x); } } else { return resolve(x); } }
测试一下
const p = new MyPromise((resolve, reject) => { setTimeout(() => { resolve("成功"); }); }); p.then((res) => { console.log("第一次then", res); // return "返回一个正常值"; // 第二次then 返回一个正常值 // return new MyPromise((resolve) => { // setTimeout(() => { // resolve("返回一个promise"); // 第二次then 返回一个promise // }); // }); throw "抛出一个异常"; // 第二次then 抛出一个异常 }).then( (res) => { console.log("第二次then", res); }, (err) => { console.log("第二次then", err); } );
实现catch
-
上面使用的时候介绍过,catch和then的第二个参数作用一样,所以catch的实现可以基于then
catch(onREJECTED) { return this.then(null, onREJECTED); }
测试一下,是没有问题的
const p = new MyPromise((resolve, reject) => { setTimeout(() => { resolve("成功了"); // reject('失败了') }); }); p.then((res) => { console.log("成功", res) throw '出错' }).catch((err) => { console.log("失败", err); });
实现finally
-
当状态变化(等待变为成功或者失败)时都会进入finally,所以,依然可以借助then实现
const p = new Promise((resolve, reject) => { setTimeout(() => { resolve(123); }); }); p.finally(() => { console.log('结束'); // 结束 });
实现all
-
该方法接收一个 Promise 数组(具有 Iterator 接口的对象),返回一个新的 Promise,该 Promise 在所有 Promise 都 resolve 后 resolve,如果其中有一个 Promise reject,则该 Promise 直接 reject。
static all(promises) { return new MyPromise((resolve, reject) => { // 创建一个空数组results,用于存储每个Promise的 resolve 结果 const results = []; let count = 0; const processResult = (index, result) => { // 结果存入results数组(具有Iterator接口的对象)中,并更新count变量 results[index] = result; count++; if (count === promises.length) { // 如果count等于Promise 数组(具有Iterator接口的对象)的长度,则说明所有Promise都resolve了,此时调用 resolve 方法 resolve(results); } }; // 遍历传入的Promise数组(具有 Iterator 接口的对象),对每个Promise调用then方法 for (const [index, promise] of [...promises].entries()) { MyPromise.resolve(promise).then((result) => { processResult(index, result); }, reject); } }); }
测试一下,没问题
function p1() { var promise1 = new MyPromise(function (resolve, reject) { console.log("p1的第一条输出语句"); resolve("p1完成"); }); return promise1; } function p2() { var promise2 = new MyPromise(function (resolve, reject) { console.log("p2的第一条输出语句"); setTimeout(() => { console.log("p2的第二条输出语句"); resolve("p2完成"); }, 2000); }); return promise2; } function p3() { var promise3 = new MyPromise(function (resolve, reject) { console.log("p3的第一条输出语句"); resolve("p3完成"); }); return promise3; } MyPromise.all([p1(), p2(), p3()]).then(function (data) { console.log(data); }); // 输出 // p1的第一条输出语句; // p2的第一条输出语句; // p3的第一条输出语句; // p2的第二条输出语句[("p1完成", "p2完成", "p3完成")];
var p1 = new MyPromise((resolve, reject) => { setTimeout(resolve, 1000, 'one'); }); var p2 = new MyPromise((resolve, reject) => { setTimeout(resolve, 2000, 'two'); }); var p3 = new MyPromise((resolve, reject) => { setTimeout(resolve, 3000, 'three'); }); var p4 = new MyPromise((resolve, reject) => { setTimeout(resolve, 4000, 'four'); }); var p5 = new MyPromise((resolve, reject) => { // reject('reject'); setTimeout(resolve, 5000, 'five'); }); MyPromise.all([p1, p2, p3, p4, p5]).then(values => { console.log(values); // [ 'one', 'two', 'three', 'four', 'five' ] }, reason => { console.log(reason) // reject }); // 5s后输出 [ 'one', 'two', 'three', 'four', 'five' ]
全部代码
class MyPromise {
static PENDING = "等待";
static FULFILLED = "成功";
static REJECTED = "失败";
constructor(func) {
this.status = MyPromise.PENDING; // 定义状态
this.result = null; // 定义返回结果
this.resloveCallbacks = []; // 存放reslove回调函数的数组
this.rejectCallbacks = []; // 存放reject回调函数的数组
// 当Promise中抛出错误时,会把promise的状态改为失败并且将错误设置为结果
try {
func(this.reslove.bind(this), this.reject.bind(this)); // 执行传入的函数
} catch (err) {
this.reject(err);
}
}
reslove(result) {
// resolve是在事件循环末尾执行的,所以这里用setTimeout包裹一下
setTimeout(() => {
this.status = MyPromise.FULFILLED; // 更改状态
this.result = result;
// 遍历执行PENDING状态时保存的reslove回调函数
this.resloveCallbacks.forEach((callback) => {
callback(result);
});
});
}
reject(result) {
// reject同样用setTimeout包裹一下
setTimeout(() => {
this.status = MyPromise.FULFILLED; // 更改状态
this.result = result;
// 遍历执行PENDING状态时保存的reject回调函数
this.rejectCallbacks.forEach((callback) => {
callback(result);
});
});
}
then(onFULFILLED, onREJECTED) {
let newPromise = new MyPromise((resolve, reject) => {
// then中两个参数可以传入undefined,做下处理
onFULFILLED =
typeof onFULFILLED === "function"
? onFULFILLED
: (value) => {
value;
};
onREJECTED =
typeof onREJECTED === "function"
? onREJECTED
: (reason) => {
throw reason;
};
if (this.status === MyPromise.PENDING) {
// PENDING状态时
this.resloveCallbacks.push(() => {
try {
let nextResult = onFULFILLED(this.result);
resolvePromise(newPromise, nextResult, resolve, reject);
} catch (err) {
reject(err);
}
});
this.rejectCallbacks.push(() => {
try {
let nextResult = onREJECTED(this.result);
resolvePromise(newPromise, nextResult, resolve, reject);
} catch (err) {
reject(err);
}
});
}
if (this.status === MyPromise.FULFILLED) {
setTimeout(() => {
try {
// 执行成功后的回调
let nextResult = onFULFILLED(this.result);
resolvePromise(newPromise, nextResult, resolve, reject);
} catch (err) {
reject(err);
}
});
}
if (this.status === MyPromise.REJECTED) {
setTimeout(() => {
try {
// 执行失败后的回调
let nextResult = onREJECTED(this.result);
resolvePromise(newPromise, nextResult, resolve, reject);
} catch (err) {
reject(err);
}
});
}
});
return newPromise;
}
catch(onREJECTED) {
return this.then(null, onREJECTED);
}
finally() {
return this.then(undefined, undefined);
}
static resolve(value) {
return new MyPromise((resolve) => {
resolve(value);
});
}
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
});
}
static all(promises) {
return new MyPromise((resolve, reject) => {
// 创建一个空数组results,用于存储每个Promise的 resolve 结果
const results = [];
let count = 0;
const processResult = (index, result) => {
// 结果存入results数组(具有Iterator接口的对象)中,并更新count变量
results[index] = result;
count++;
if (count === promises.length) {
// 如果count等于Promise 数组(具有Iterator接口的对象)的长度,则说明所有Promise都resolve了,此时调用 resolve 方法
resolve(results);
}
};
// 遍历传入的Promise数组(具有 Iterator 接口的对象),对每个Promise调用then方法
for (const [index, promise] of [...promises].entries()) {
Promise.resolve(promise).then((result) => {
processResult(index, result);
}, reject);
}
});
}
}
function resolvePromise(newPromise, x, resolve, reject) {
if (x === newPromise) {
// 因为x是回调的结果值,如果x指向newPromise即自己,那么会重新解析自己,导致循环调用
throw new TypeError("禁止循环调用");
}
// 如果x是一个Promise,我们必须等它完成(失败或成功)后得到一个普通值时,才能继续执行。
// 那我们把要执行的任务放在x.then()的成功回调和失败回调里面即可
// 这就表示x完成后就会调用我们的代码。
// 但是对于成功的情况,我们还需要再考虑下,x.then成功回调函数的参数,我们称为y
// 那y也可能是一个thenable对象或者promise
// 所以如果成功时,执行resolvePromise(promise2, y, resolve, reject)
// 并且传入resolve, reject,当解析到普通值时就resolve出去,反之继续解析
// 这样子用于保证最后resolve的结果一定是一个非promise类型的参数
if (x instanceof MyPromise) {
x.then(
(y) => {
resolvePromise(newPromise, y, resolve, reject);
},
(r) => reject(r)
);
}
// (x instanceof myPromise) 处理了promise的情况,但是很多时候交互的promise可能不是原生的
// 就像我们现在写的一个myPromise一样,这种有then方法的对象或函数我们称为thenable。
// 因此我们需要处理thenable。
else if ((typeof x === "object" || typeof x === "function") && x !== null) {
// 暂存x这个对象或函数的then,x也可能没有then,那then就会得到一个undefined
try {
var then = x.then;
} catch (e) {
// 如果读取then的过程中出现异常则reject异常出去
return reject(e);
}
// 判断then是否函数且存在,如果函数且存在那这个就是合理的thenable,我们要尝试去解析
if (typeof then === "function") {
// 状态只能更新一次使用一个called防止反复调用
// 因为成功和失败的回调只能执行其中之一
let called = false;
try {
then.call(
x,
(y) => {
// called就是用于防止成功和失败被同时执行,因为这个是thenable,不是promise
// 需要做限制如果newPromise已经成功或失败了,则不会再处理了
if (called) return;
called = true;
resolvePromise(newPromise, y, resolve, reject);
},
(r) => {
// called就是用于防止成功和失败被同时执行,因为这个是thenable,不是promise
// 需要做限制如果newPromise已经成功或失败了,则不会再处理了
if (called) return;
called = true;
reject(r);
}
);
// 上面那一步等价于,即这里把thenable当作类似于promise的对象去执行then操作
// x.then(
// (y) => {
// if (called) return;
// called = true;
// resolvePromise(newPromise, y, resolve, reject);
// },
// (r) => {
// if (called) return;
// called = true;
// reject(r);
// }
// )
} catch (e) {
// called就是用于防止成功和失败被同时执行,因为这个是thenable,不是promise
// 需要做限制如果newPromise已经成功或失败了,则不会再处理了
if (called) return;
called = true;
reject(e);
}
} else {
// 如果是对象或函数但不是thenable(即没有正确的then属性)
// 当成普通值则直接resolve出去
resolve(x);
}
} else {
return resolve(x);
}
}