1、使用class
平常用 promise 的时候, 是通过 new 关键字来 new Promise(), 所以咱们应该用构造函数或者 class 来实现. 都 2021 年了, 咱们就用 class 来实现一下吧.
1class MPromise {2 constructor() {}3}
2. 定义三种状态类型
1const PENDING = "pending";2const FULFILLED = "fulfilled";3const REJECTED = "rejected";
3. 设置初始状态
1class MPromise {2 constructor() {3 // 初始状态为pending4 this.status = PENDING;5 this.value = null;6 this.reason = null;7 }8}
4. resolve 和 reject 方法
4.1. 根据A+的规范, 这两个方法是要更改 status 的, 从 pending 改到 fulfilled/rejected. 4.2. 注意两个函数的入参分别是 value 和 reason.
1class MPromise {2 constructor() {3 // 初始状态为pending4 this.status = PENDING;5 this.value = null;6 this.reason = null;7 }89 resolve(value) {10 if (this.status === PENDING) {11 this.value = value;12 this.status = FULFILLED;13 }14 }1516 reject(reason) {17 if (this.status === PENDING) {18 this.reason = reason;19 this.status = REJECTED;20 }21 }22}
5. promise入参
5.1. 入参是一个函数, 函数接收 resolve 和 reject 两个参数. 5.2. 注意在初始化 promise 的时候, 就要执行这个函数, 并且有任何报错都要通过 reject 抛出去
1class MPromise {2 constructor(fn) {3 // 初始状态为pending4 this.status = PENDING;5 this.value = null;6 this.reason = null;78 try {9 fn(this.resolve.bind(this), this.reject.bind(this));10 } catch (e) {11 this.reject(e);12 }13 }1415 resolve(value) {16 if (this.status === PENDING) {17 this.value = value;18 this.status = FULFILLED;19 }20 }2122 reject(reason) {23 if (this.status === PENDING) {24 this.reason = reason;25 this.status = REJECTED;26 }27 }28}
6. then 方法
6.1. then 接收两个参数, onFulfilled 和 onRejected
1then(onFulfilled, onRejected) {}
6.2. 检查并处理参数, 之前提到的如果不是 function, 就忽略. 这个忽略指的是原样返回 value 或者 reason.
1isFunction(param) {2 return typeof param === 'function';3}45then(onFulfilled, onRejected) {6 const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => {7 return value8 }9 const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {10 throw reason;11 };12}
6.3. 要知道.then 的返回值整体是一个 promise, 所以咱们先用 promise 来包裹一下, 其他逻辑待会再实现.
1then(onFulfilled, onRejected) {2 const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => {3 return value4 }5 const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {6 throw reason;7 };8 const promise2 = new MPromise((resolve, reject) => {})9 return promise210}
6.4. 根据当前 promise 的状态, 调用不同的函数
1then(onFulfilled, onRejected) {2 const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => {3 return value4 }5 const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {6 throw reason;7 };8 const promise2 = new MPromise((resolve, reject) => {9 switch (this.status) {10 case FULFILLED: {11 realOnFulfilled()12 break;13 }14 case REJECTED: {15 realOnRejected()16 break;17 }18 }19 })20 return promise22122}
6.5. 这样写, 是在 then 函数被调用的瞬间就会执行. 那这时候如果 status 还没变成 fulfilled 或者 rejected 怎么办, 很有可能还是 pending 的. 所以我们需要一个状态的监听机制, 当状态变成 fulfilled 或者 rejected 后, 再去执行 callback.
6.5.1. 那么我们首先要拿到所有的 callback, 然后才能在某个时机去执行他. 新建两个数组, 来分别存储成功和失败的回调, 调用 then 的时候, 如果还是 pending 就存入数组.
1FULFILLED_CALLBACK_LIST = [];2REJECTED_CALLBACK_LIST = [];34then(onFulfilled, onRejected) {5const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => {6 return value7}8const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {9 throw reason;10};11const promise2 = new MPromise((resolve, reject) => {12 switch (this.status) {13 case FULFILLED: {14 realOnFulfilled()15 break;16 }17 case REJECTED: {18 realOnRejected()19 break;20 }21 case PENDING: {22 this.FULFILLED_CALLBACK_LIST.push(realOnFulfilled)23 this.REJECTED_CALLBACK_LIST.push(realOnRejected)24 }25 }26})27return promise22829}
6.5.2. 在 status 发生变化的时候, 就执行所有的回调. 这里咱们用一下 es6 的 getter 和 setter. 这样更符合语义, 当 status 改变时, 去做什么事情. (当然也可以顺序执行, 在给 status 赋值后, 下面再加一行 forEach)
1_status = PENDING;23get status() {4 return this._status;5}67set status(newStatus) {8 this._status = newStatus;9 switch (newStatus) {10 case FULFILLED: {11 this.FULFILLED_CALLBACK_LIST.forEach(callback => {12 callback(this.value);13 });14 break;15 }16 case REJECTED: {17 this.REJECTED_CALLBACK_LIST.forEach(callback => {18 callback(this.reason);19 });20 break;21 }22 }23}
7. then 的返回值
上面只是简单说了下, then 的返回值是一个 Promise, 那么接下来具体讲一下返回 promise 的 value 和 reason 是什么.
7.1. 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e。(这样的话, 我们就需要手动 catch 代码,遇到报错就 reject)
1then(onFulfilled, onRejected) {2 const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => {3 return value4 }5 const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {6 throw reason;7 };8 const promise2 = new MPromise((resolve, reject) => {9 const fulfilledMicrotask = () => {10 try {11 realOnFulfilled(this.value);12 } catch (e) {13 reject(e)14 }15 };16 const rejectedMicrotask = () => {17 try {18 realOnRejected(this.reason);19 } catch (e) {20 reject(e);21 }22 }2324 switch (this.status) {25 case FULFILLED: {26 fulfilledMicrotask()27 break;28 }29 case REJECTED: {30 rejectedMicrotask()31 break;32 }33 case PENDING: {34 this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask)35 this.REJECTED_CALLBACK_LIST.push(rejectedMicrotask)36 }37 }38 })39 return promise240}
7.2 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值
7.3 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因。
需要注意的是,如果 promise1 的 onRejected 执行成功了,promise2 应该被 resolve
这里咱们其实已经在参数检查的时候做过了, 也就是这段代码
1const realOnFulfilled = this.isFunction(onFulfilled)2 ? onFulfilled3 : (value) => {4 return value;5 };6const realOnRejected = this.isFunction(onRejected)7 ? onRejected8 : (reason) => {9 throw reason;10 };
7.4 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行 resolvePromise 方法
1then(onFulfilled, onRejected) {2 const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => {3 return value4 }5 const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {6 throw reason;7 };8 const promise2 = new MPromise((resolve, reject) => {9 const fulfilledMicrotask = () => {10 try {11 const x = realOnFulfilled(this.value);12 this.resolvePromise(promise2, x, resolve, reject);13 } catch (e) {14 reject(e)15 }16 };17 const rejectedMicrotask = () => {18 try {19 const x = realOnRejected(this.reason);20 this.resolvePromise(promise2, x, resolve, reject);21 } catch (e) {22 reject(e);23 }24 }2526 switch (this.status) {27 case FULFILLED: {28 fulfilledMicrotask()29 break;30 }31 case REJECTED: {32 rejectedMicrotask()33 break;34 }35 case PENDING: {36 this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask)37 this.REJECTED_CALLBACK_LIST.push(rejectedMicrotask)38 }39 }40 })41 return promise242}
8. resolvePromise
1resolvePromise(promise2, x, resolve, reject) {2 // 如果 newPromise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 newPromise3 // 这是为了防止死循环4 if (promise2 === x) {5 return reject(new TypeError('The promise and the return value are the same'));6 }78 if (x instanceof MPromise) {9 // 如果 x 为 Promise ,则使 newPromise 接受 x 的状态10 // 也就是继续执行x,如果执行的时候拿到一个y,还要继续解析y11 queueMicrotask(() => {12 x.then((y) => {13 this.resolvePromise(promise2, y, resolve, reject);14 }, reject);15 })16 } else if (typeof x === 'object' || this.isFunction(x)) {17 // 如果 x 为对象或者函数18 if (x === null) {19 // null也会被判断为对象20 return resolve(x);21 }2223 let then = null;2425 try {26 // 把 x.then 赋值给 then27 then = x.then;28 } catch (error) {29 // 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise30 return reject(error);31 }3233 // 如果 then 是函数34 if (this.isFunction(then)) {35 let called = false;36 // 将 x 作为函数的作用域 this 调用37 // 传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise38 try {39 then.call(40 x,41 // 如果 resolvePromise 以值 y 为参数被调用,则运行 resolvePromise42 (y) => {43 // 需要有一个变量called来保证只调用一次.44 if (called) return;45 called = true;46 this.resolvePromise(promise2, y, resolve, reject);47 },48 // 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise49 (r) => {50 if (called) return;51 called = true;52 reject(r);53 });54 } catch (error) {55 // 如果调用 then 方法抛出了异常 e:56 if (called) return;5758 // 否则以 e 为据因拒绝 promise59 reject(error);60 }61 } else {62 // 如果 then 不是函数,以 x 为参数执行 promise63 resolve(x);64 }65 } else {66 // 如果 x 不为对象或者函数,以 x 为参数执行 promise67 resolve(x);68 }69}
9. onFulfilled 和 onRejected 是微任务
咱们可以用 queueMicrotask 包裹执行函数
1const fulfilledMicrotask = () => {2 queueMicrotask(() => {3 try {4 const x = realOnFulfilled(this.value);5 this.resolvePromise(promise2, x, resolve, reject);6 } catch (e) {7 reject(e);8 }9 });10};11const rejectedMicrotask = () => {12 queueMicrotask(() => {13 try {14 const x = realOnRejected(this.reason);15 this.resolvePromise(promise2, x, resolve, reject);16 } catch (e) {17 reject(e);18 }19 });20};
10. 简单写点代码测试一下
1const test = new MPromise((resolve, reject) => {2 setTimeout(() => {3 resolve(111);4 }, 1000);5}).then(console.log);67console.log(test);89setTimeout(() => {10 console.log(test);11}, 2000);
11. catch 方法
1catch (onRejected) {2 return this.then(null, onRejected);3}
12. promise.resolve
将现有对象转为 Promise 对象,如果 Promise.resolve 方法的参数,不是具有 then 方法的对象(又称 thenable 对象),则返回一个新的 Promise 对象,且它的状态为 fulfilled。 注意这是一个静态方法, 因为咱们是通过 Promise.resolve 调用的, 而不是通过实例去调用的.
1static resolve(value) {2 if (value instanceof MPromise) {3 return value;4 }56 return new MPromise((resolve) => {7 resolve(value);8 });9}
13. promise.reject
返回一个新的 Promise 实例,该实例的状态为 rejected。Promise.reject 方法的参数 reason,会被传递给实例的回调函数。
1static reject(reason) {2 return new MPromise((resolve, reject) => {3 reject(reason);4 });5}
14. promise.race
const p = Promise.race([p1, p2, p3]);
该方法是将多个 Promise 实例,包装成一个新的 Promise 实例。 只要 p1、p2、p3 之中有一个实例率先改变状态,p 的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给 p 的回调函数。
1static race(promiseList) {2 return new MPromise((resolve, reject) => {3 const length = promiseList.length;45 if (length === 0) {6 return resolve();7 } else {8 for (let i = 0; i < length; i++) {9 MPromise.resolve(promiseList[i]).then(10 (value) => {11 return resolve(value);12 },13 (reason) => {14 return reject(reason);15 });16 }17 }18 });1920}
写段测试代码
1const test = new MPromise((resolve, reject) => {2 setTimeout(() => {3 resolve(111);4 }, 1000);5});67const test2 = new MPromise((resolve, reject) => {8 setTimeout(() => {9 resolve(222);10 }, 2000);11});1213const test3 = new MPromise((resolve, reject) => {14 setTimeout(() => {15 resolve(333);16 }, 3000);17});1819MPromise.race([test, test2, test3]).then(console.log);
all
- 接收一个Promise数组,数组中如有非Promise项,则此项当做成功
- 如果所有Promise都成功,则返回成功结果数组
- 如果有一个Promise失败,则返回这个失败结果
1static all(promises) {2 const result = []3 let count = 04 return new MyPromise((resolve, reject) => {5 const addData = (index, value) => {6 result[index] = value7 count++8 if (count === promises.length) resolve(result)9 }10 promises.forEach((promise, index) => {11 if (promise instanceof MyPromise) {12 promise.then(res => {13 addData(index, res)14 }, err => reject(err))15 } else {16 addData(index, promise)17 }18 })19 })20}
race
- 接收一个Promise数组,数组中如有非Promise项,则此项当做成功
- 哪个Promise最快得到结果,就返回那个结果,无论成功失败
1static race(promises) {2 return new MyPromise((resolve, reject) => {3 promises.forEach(promise => {4 if (promise instanceof MyPromise) {5 promise.then(res => {6 resolve(res)7 }, err => {8 reject(err)9 })10 } else {11 resolve(promise)12 }13 })14 })15}
allSettled
- 接收一个Promise数组,数组中如有非Promise项,则此项当做成功
- 把每一个Promise的结果,集合成数组,返回
1static allSettled(promises) {2 return new Promise((resolve, reject) => {3 const res = []4 let count = 05 const addData = (status, value, i) => {6 res[i] = {7 status,8 value9 }10 count++11 if (count === promises.length) {12 resolve(res)13 }14 }15 promises.forEach((promise, i) => {16 if (promise instanceof MyPromise) {17 promise.then(res => {18 addData('fulfilled', res, i)19 }, err => {20 addData('rejected', err, i)21 })22 } else {23 addData('fulfilled', promise, i)24 }25 })26 })27}
any
any与all相反
- 接收一个Promise数组,数组中如有非Promise项,则此项当做成功
- 如果有一个Promise成功,则返回这个成功结果
- 如果所有Promise都失败,则报错
1static any(promises) {2 return new Promise((resolve, reject) => {3 let count = 04 promises.forEach((promise) => {5 promise.then(val => {6 resolve(val)7 }, err => {8 count++9 if (count === promises.length) {10 reject(new AggregateError('All promises were rejected'))11 }12 })13 })14 })15 }16}