手写promise思路

之前写过一篇关于promise的一些常规用法,以及promise与async/await关系的文章。但是我们知道,要想把一个知识点完全掌握,知其然而不知其所以然是远远不够的,那么接下来将要来探讨promise的原理,来分析分析promise的这种规则机制是如何实现的。我们通过手写promise的方式达到这个目的,同时来加深对primise的理解。

思路

手写promise之前,我们先来回忆一下promise的使用方式,便于整理思路。

const p1 = new Promise((resolve, reject)=>{
  console.log('此处同步执行');
  const a = 2;
  setTimeout(()=>{
  // 此处异步执行
  if(a>0){
    resolve('成功');
  }else{
    reject('失败原因');
  }
  },1000)
});
p1.then((res)=>{
  console.log(res);
},(err)=>{
  console.log(err);
})

从上面的代码可以看出,要想使用promise需要先通过new Promise(fn)生成一个实例p1,然后通过实例p1调用then()catch()方法。因此可以得出以下几点结论:

  1. Promise本身是一个构造函数,其参数fn是一个同步执行的回调函数,该函数执行的参数也是两个函数resolvereject。这两个参数的作用是等异步操作执行完成后,为后续方法的执行传参,如:then()catch()
  2. then()用两个函数作为参数,在实例p1中的resolvereject方法中分别触发对应的函数,并把异步操作执行的结果传递给对应的函数。
  3. Promise有三种状态:pendingrejectedresolved,同步回调函数fn开始执行时状态为pending,执行了resolvereject后会将其状态改为resolvedrejected。resolved和rejected只能执行一次,且Promise状态一旦被确定下来,那么就是不可更改的(锁定)。

通过观察Promise的使用方式得出的几点结论,书写promise的思路大致可以通过下面几个方面来完成:

  1. 定义Promise的三种状态;
  2. 创建构造函数,并为构造函数定义一个回调函数作为参数;
  3. 在构造函数内定义变量来保存Promise的状态,定义两个函数resolvereject,并在构造函数中执行回调函数的时候将此传入;
  4. 函数resolvereject目前的作用是改变Promise的状态,保存异步操作返回的值或者失败的原因;
  5. 为构造函数创建then()方法,then()方法的参数是两个函数onResolvedonRejected,这两个函数将被传入构造函数内定义的resolvereject方法中执行。此时函数resolvereject发挥了它的第二个作用,就是执行then()方法传递过来的回调函数。

实现

有了大致的思路,那么接下来就是如何去实现它。

  1. Promise构造函数的设计,对应思路1、2、3、4
const PROMISE_STATUS_PENDING = 'pending';
const PROMISE_STATUS_FULFILLED = 'fulfilled';
const PROMISE_STATUS_REJECTED = 'rejected';
class myPromise {
    // * 记录状态
    constructor(executor) {
        // * 保存Promise的状态
        this.status = PROMISE_STATUS_PENDING;
        // * 保存传入的值
        this.value = undefined;
        this.reason = undefined;
        const resolve = value => {
            if (this.status == PROMISE_STATUS_PENDING) {
                this.status = PROMISE_STATUS_FULFILLED;
                this.value = value;
                console.log('resolve被调用');
            }
        };
        const reject = reason => {
            if (this.status == PROMISE_STATUS_PENDING) {
                this.status = PROMISE_STATUS_REJECTED;
                this.reason = reason;
                console.log('reject被调用');
            }
        };
        executor(resolve, reject);
    }
}
  1. 定义好构造函数,接下来的任务就是书写构造函数的方法了,对应5。修改上面的代码如下:
const PROMISE_STATUS_PENDING = 'pending';
const PROMISE_STATUS_FULFILLED = 'fulfilled';
const PROMISE_STATUS_REJECTED = 'rejected';
class myPromise {
    // * 记录状态
    constructor(executor) {
        // * 保存Promise的状态
        this.status = PROMISE_STATUS_PENDING;
        // * 保存传入的值
        this.value = undefined;
        this.reason = undefined;
        const resolve = value => {
            if (this.status == PROMISE_STATUS_PENDING) {
                this.status = PROMISE_STATUS_FULFILLED;
                //* 定时器是一个宏任务,会放在下一次事件循环时使用
                queueMicrotask(() => {
                    this.value = value;
                    console.log('resolve被调用', this.value);
                    // * 执行then传入进来的第一个回调函数
                    this.onResolved(this.value);
                });
            }
        };
        const reject = reason => {
            if (this.status == PROMISE_STATUS_PENDING) {
                this.status = PROMISE_STATUS_REJECTED;
                queueMicrotask(() => {
                    this.reason = reason;
                    console.log('reject被调用', this.reason);
                    // * 执行then传入进来的第二个回调函数
                    this.onRejected(this.reason);
                });
            }
        };
        executor(resolve, reject);
    }
    // then方法
    then(onResolved, onRejected) {
        this.onResolved = onResolved;
        this.onRejected = onRejected;
    }
}

优化

完成以上代码已经搭建了一个具备基本功能的Promise,不防试一下,相信它会带给你满意的结果。

const promise = new myPromise((resolve, reject) => {
    console.log('状态pending');
    resolve('1111');
});
promise.then(
    res => {
        console.log('res:', res);
    },
    err => {
        console.log('err:', err);
    },
);

运行以上代码,命令行会相继输出状态pendingresolve被调用 1111res: 1111等,这代表着最基础版的Promise已经完成了。但是它仍然有很多问题,比如then()方法无法多次调用和链式调用、没有catch()方法等,所以接下来我们就要优化上面基础版的Promise,使它具备和官方基本一致的功能。

  1. 实现then()的多次调用
    then()多次调用就需要在构造函数里定义两个数组保存then()方法中传进来的回调,然后遍历这个数组,执行数组里的所有回调函数,修改代码如下:
const PROMISE_STATUS_PENDING = 'pending';
const PROMISE_STATUS_FULFILLED = 'fulfilled';
const PROMISE_STATUS_REJECTED = 'rejected';
class myPromise {
    // * 记录状态
    constructor(executor) {
        // * 保存Promise的状态
        this.status = PROMISE_STATUS_PENDING;
        // * 保存传入的值
        this.value = undefined;
        this.reason = undefined;
        this.onResolvedFns = [];
        this.onRejectedFns = [];
        const resolve = value => {
            if (this.status == PROMISE_STATUS_PENDING) {
                //* 定时器是一个宏任务,会放在下一次事件循环时使用
                queueMicrotask(() => {
                    this.status = PROMISE_STATUS_FULFILLED;
                    this.value = value;
                    console.log('resolve被调用', this.value);
                    // * 执行then传入进来的第一个回调函数
                    this.onResolvedFns.forEach(Fn => {
                        Fn(this.value);
                    });
                });
            }
        };
        const reject = reason => {
            if (this.status == PROMISE_STATUS_PENDING) {
                queueMicrotask(() => {
                    this.status = PROMISE_STATUS_REJECTED;
                    this.reason = reason;
                    console.log('reject被调用', this.reason);
                    // * 执行then传入进来的第二个回调函数
                    this.onRejectedFns.forEach(Fn => {
                        Fn(this.reason);
                    });
                });
            }
        };
        executor(resolve, reject);
    }
    // then方法
    then(onResolved, onRejected) {
        console.log(this.status);
        // 如果then方法调用的时候,状态已经确定下来了,应该直接执行的
        if (this.status === PROMISE_STATUS_FULFILLED && onResolved) {
            onResolved(this.value);
        } else if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
            onRejected(this.reason);
        } else {
            // 将成功回调和失败回调添加到数组中
            this.onResolvedFns.push(onResolved);
            this.onRejectedFns.push(onRejected);
        }
    }
}
  1. 实现then()的链式调用
    从上面的代码中可以清楚的看到then()方法是挂载在构造函数myPromise上的,所以为了实现链式调用,需要在then()方法里返回一个新的Promise对象,然后使用新的Promise对象的resolve方法去处理对应的回调函数的返回值。从代码的简洁度考虑,我们需要封装一个工具函数,用来处理异常和回调函数。
    与此同时,当回调函数executor的执行发生异常时,也许有执行reject|函数。因此,我们把代码调整如下:
const PROMISE_STATUS_PENDING = 'pending';
const PROMISE_STATUS_FULFILLED = 'fulfilled';
const PROMISE_STATUS_REJECTED = 'rejected';

// 工具函数
function execFunctionWithCatchError(exeFn, value, resolve, reject) {
    try {
        let result = exeFn(value);
        resolve(result);
    } catch (err) {
        reject(err);
    }
}

class myPromise {
    // * 记录状态
    constructor(executor) {
        // * 保存Promise的状态
        this.status = PROMISE_STATUS_PENDING;
        // * 保存传入的值
        this.value = undefined;
        this.reason = undefined;
        this.onResolvedFns = [];
        this.onRejectedFns = [];
        const resolve = value => {
            if (this.status == PROMISE_STATUS_PENDING) {
                // * 添加微任务
                //* 定时器是一个宏任务,会放在下一次事件循环时使用
                queueMicrotask(() => {
                    if (this.status !== PROMISE_STATUS_PENDING) return;
                    this.status = PROMISE_STATUS_FULFILLED;
                    this.value = value;
                    // console.log('resolve被调用', this.value);
                    // * 执行then传入进来的第一个回调函数
                    this.onResolvedFns.forEach(Fn => {
                        Fn(this.value);
                    });
                });
            }
        };
        const reject = reason => {
            if (this.status == PROMISE_STATUS_PENDING) {
                //  * 添加微任务
                queueMicrotask(() => {
                    if (this.status !== PROMISE_STATUS_PENDING) return;
                    this.status = PROMISE_STATUS_REJECTED;
                    this.reason = reason;
                    // console.log('reject被调用', this.reason);
                    // * 执行then传入进来的第二个回调函数
                    this.onRejectedFns.forEach(Fn => {
                        Fn(this.reason);
                    });
                });
            }
        };
        // * 在调用executor时判断里面是否抛出异常
        try {
            executor(resolve, reject);
        } catch (err) {
            reject(err);
        }
    }
    // then方法
    then(onResolved, onRejected) {
        return new myPromise((resolve, reject) => {
            // 如果then方法调用的时候,状态已经确定下来了,应该直接执行的
            if (this.status === PROMISE_STATUS_FULFILLED && onResolved) {
                // onResolved(this.value);
                execFunctionWithCatchError(onResolved, this.value, resolve, reject);
            } else if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
                // onRejected(this.reason);
                execFunctionWithCatchError(
                    onRejected,
                    this.reason,
                    resolve,
                    reject,
                );
            } else {
                // 将成功回调和失败回调添加到数组中
                this.onResolvedFns.push(() => {
                    execFunctionWithCatchError(
                        onResolved,
                        this.value,
                        resolve,
                        reject,
                    );
                });
                this.onRejectedFns.push(() => {
                    execFunctionWithCatchError(
                        onRejected,
                        this.reason,
                        resolve,
                        reject,
                    );
                });
            }
        });
    }
}
  1. catch()方法的实现
    我们知道,在官方提供的Promise中可不止then()一种方法,其中最常用的便是catch()方法了。
    catch()then()方法不同,它只会接受一个onRejected的回调函数,catch()方法执行的其实是then()方法第二个参数的工作,then(null, function() {})就等同于catch(function() {})。但是用this.then(undefined,onRejected);来实现catch()方法显然是不可以的,因为这样做的话,catch()方法是针对新的Promiserejected的状态,我们要解决的问题就是如何让catch()方法捕获原Promise对象的rejected状态。
    所以我们要对then()方法做一些改动,在方法内部前面判断第二个参数是否有值,如果没有值,就重新赋值为一个函数,函数内部抛出一个异常。这样在新的Promise就能捕获到原来的promiserejected的状态了。具体实现方式如下:
const PROMISE_STATUS_PENDING = 'pending';
const PROMISE_STATUS_FULFILLED = 'fulfilled';
const PROMISE_STATUS_REJECTED = 'rejected';

// 工具函数
function execFunctionWithCatchError(exeFn, value, resolve, reject) {
    try {
        let result = exeFn(value);
        resolve(result);
    } catch (err) {
        reject(err);
    }
}

class myPromise {
    // * 记录状态
    constructor(executor) {
        // * 保存Promise的状态
        this.status = PROMISE_STATUS_PENDING;
        // * 保存传入的值
        this.value = undefined;
        this.reason = undefined;
        this.onResolvedFns = [];
        this.onRejectedFns = [];
        const resolve = value => {
            if (this.status == PROMISE_STATUS_PENDING) {
                // * 添加微任务
                //* 定时器是一个宏任务,会放在下一次事件循环时使用
                queueMicrotask(() => {
                    if (this.status !== PROMISE_STATUS_PENDING) return;
                    this.status = PROMISE_STATUS_FULFILLED;
                    this.value = value;
                    // console.log('resolve被调用', this.value);
                    // * 执行then传入进来的第一个回调函数
                    this.onResolvedFns.forEach(Fn => {
                        Fn(this.value);
                    });
                });
            }
        };
        const reject = reason => {
            if (this.status == PROMISE_STATUS_PENDING) {
                //  * 添加微任务
                queueMicrotask(() => {
                    if (this.status !== PROMISE_STATUS_PENDING) return;
                    this.status = PROMISE_STATUS_REJECTED;
                    this.reason = reason;
                    // console.log('reject被调用', this.reason);
                    // * 执行then传入进来的第二个回调函数
                    this.onRejectedFns.forEach(Fn => {
                        Fn(this.reason);
                    });
                });
            }
        };
        // * 在调用executor时判断里面是否抛出异常
        try {
            executor(resolve, reject);
        } catch (err) {
            reject(err);
        }
    }
    // then方法
    then(onResolved, onRejected) {
        onRejected =
            onRejected ||
            (err => {
                throw err;
            });
        return new myPromise((resolve, reject) => {
            // 如果then方法调用的时候,状态已经确定下来了,应该直接执行的
            if (this.status === PROMISE_STATUS_FULFILLED && onResolved) {
                // onResolved(this.value);
                execFunctionWithCatchError(onResolved, this.value, resolve, reject);
            } else if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
                // onRejected(this.reason);
                execFunctionWithCatchError(
                    onRejected,
                    this.reason,
                    resolve,
                    reject,
                );
            } else {
                // 将成功回调和失败回调添加到数组中
                if (onResolved)
                    this.onResolvedFns.push(() => {
                        execFunctionWithCatchError(
                            onResolved,
                            this.value,
                            resolve,
                            reject,
                        );
                    });
                if (onRejected)
                    this.onRejectedFns.push(() => {
                        execFunctionWithCatchError(
                            onRejected,
                            this.reason,
                            resolve,
                            reject,
                        );
                    });
            }
        });
    }
    // * catch方法
    catch(onRejected) {
        this.then(undefined, onRejected);
    }
}
  1. finally()方法的实现
    前面讲到的then()catch()都是Promise的实例方法,也可以称为对象方法,除此之外,Promise还有一个实例方法,那就是finally()finally()方法大致可以概括如下:
  • finally是ES9(ES2018)新增的一个特性:表示无论Promise的状态变为resolved还是reject,最终都会被执行的代码。
  • finally方法是不接收参数的,因为无论前面是resolved状态,还是reject状态,它都会执行。
  • finally其实也是返回一个Promise对象,但是其实很少人会用它。
    因此,finally方法的实现也很简单,只需要在Promise构造函数中定义一个方法,无论promise的状态是什么。代码实现如下:
const PROMISE_STATUS_PENDING = 'pending';
const PROMISE_STATUS_FULFILLED = 'fulfilled';
const PROMISE_STATUS_REJECTED = 'rejected';

// 工具函数
function execFunctionWithCatchError(exeFn, value, resolve, reject) {
    try {
        let result = exeFn(value);
        resolve(result);
    } catch (err) {
        reject(err);
    }
}

class myPromise {
    // * 记录状态
    constructor(executor) {
        // * 保存Promise的状态
        this.status = PROMISE_STATUS_PENDING;
        // * 保存传入的值
        this.value = undefined;
        this.reason = undefined;
        this.onResolvedFns = [];
        this.onRejectedFns = [];
        const resolve = value => {
            if (this.status == PROMISE_STATUS_PENDING) {
                // * 添加微任务
                //* 定时器是一个宏任务,会放在下一次事件循环时使用
                queueMicrotask(() => {
                    if (this.status !== PROMISE_STATUS_PENDING) return;
                    this.status = PROMISE_STATUS_FULFILLED;
                    this.value = value;
                    // console.log('resolve被调用', this.value);
                    // * 执行then传入进来的第一个回调函数
                    this.onResolvedFns.forEach(Fn => {
                        Fn(this.value);
                    });
                });
            }
        };
        const reject = reason => {
            if (this.status == PROMISE_STATUS_PENDING) {
                //  * 添加微任务
                queueMicrotask(() => {
                    if (this.status !== PROMISE_STATUS_PENDING) return;
                    this.status = PROMISE_STATUS_REJECTED;
                    this.reason = reason;
                    // console.log('reject被调用', this.reason);
                    // * 执行then传入进来的第二个回调函数
                    this.onRejectedFns.forEach(Fn => {
                        Fn(this.reason);
                    });
                });
            }
        };
        // * 在调用executor时判断里面是否抛出异常
        try {
            executor(resolve, reject);
        } catch (err) {
            reject(err);
        }
    }
    // then方法
    then(onResolved, onRejected) {
        onRejected =
            onRejected ||
            (err => {
                throw err;
            });
        return new myPromise((resolve, reject) => {
            // 如果then方法调用的时候,状态已经确定下来了,应该直接执行的
            if (this.status === PROMISE_STATUS_FULFILLED && onResolved) {
                // onResolved(this.value);
                execFunctionWithCatchError(onResolved, this.value, resolve, reject);
            } else if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
                // onRejected(this.reason);
                execFunctionWithCatchError(
                    onRejected,
                    this.reason,
                    resolve,
                    reject,
                );
            } else {
                // 将成功回调和失败回调添加到数组中
                if (onResolved)
                    this.onResolvedFns.push(() => {
                        execFunctionWithCatchError(
                            onResolved,
                            this.value,
                            resolve,
                            reject,
                        );
                    });
                if (onRejected)
                    this.onRejectedFns.push(() => {
                        execFunctionWithCatchError(
                            onRejected,
                            this.reason,
                            resolve,
                            reject,
                        );
                    });
            }
        });
    }
    // * catch方法
    catch(onRejected) {
        this.then(undefined, onRejected);
    }
    // finally方法
    finally(onFinally) {
        return this.then(
            () => {
                onFinally();
            },
            () => {
                onFinally();
            },
        );
    }
}
  1. Promise的类方法的实现
    前面说到的thencatchfinally方法都属于Promise的实例方法,都是存放在Promiseprototype上的。下面我们将学习类方法。
  • Promise.resolve()方法:有时候我们已经有一个现成的内容,希望将其转成Promise来使用,这个时候我们可以使用Promise.resolve()方法来完成,所以Promise.resolve()相当于new Promise,并且执行resolve操作。
  • Promise.reject()方法:reject方法类似于resolve方法,只是会将Promise对象的状态设置为rejected状态,所以Promise.reject无论传过来的参数是什么状态,都会直接作为reject的参数传递到catch的。
  • Promise.all()方法:Promise.all()我们在上一篇中讲过,对于用法这里不再多做阐述,大致可以归纳为只有当所有的promise都变成resolved状态时,原promise才会变成resolved状态,相反当任意一个promise变成rejected状态时,原promise就会变成rejected状态,并且仍然处于pending状态的promise将不会获取到结果。不明白的同学请自行查阅Promise 与async/await
  • Promise.allSettled()方法:Promise.allSettled是ES11(ES2020)中新添加的API,它用于解决Promise.all()方法的一个缺陷(也是其特征):当有一个Promise变成rejected状态时,新Promise就会立即变成对应的rejected状态。 Promise.allSettled方法会在所有的Promise都有结果时,无论是resolved,还是rejected,才会有最终的状态,并且这个Promise的结果一定是resolved`。
  • Promise.race()方法:Promise.race()方法同样在上一篇中讲过,大致可以归纳为:数组中的其中一个promise返回状态时,无论此状态是resolved或者rejected,它都将会成为原promise的状态,即先到先得。
  • Promise.any()方法:Promise.any()方法是ES12中新增的方法,和Promise.race()方法是类似的。Promise.any()方法会等到一个resolved状态,才会决定新Promise的状态,就算所有的Promise都是rejected的,那么也会等到所有的Promise都变成rejected状态,err信息为:AggregateError: All promises were rejected
    看完所有Promise类方法的使用,接下来我们就开下怎么来实现他们吧。
const PROMISE_STATUS_PENDING = 'pending';
const PROMISE_STATUS_FULFILLED = 'fulfilled';
const PROMISE_STATUS_REJECTED = 'rejected';

// 工具函数
function execFunctionWithCatchError(exeFn, value, resolve, reject) {
    try {
        const result = exeFn(value);
        resolve(result);
    } catch (err) {
        reject(err);
    }
}

class myPromise {
    // * 记录状态
    constructor(executor) {
        // * 保存Promise的状态
        this.status = PROMISE_STATUS_PENDING;
        // * 保存传入的值
        this.value = undefined;
        this.reason = undefined;
        this.onResolvedFns = [];
        this.onRejectedFns = [];
        const resolve = value => {
            if (this.status == PROMISE_STATUS_PENDING) {
                // * 添加微任务
                //* 定时器是一个宏任务,会放在下一次事件循环时使用
                queueMicrotask(() => {
                    if (this.status !== PROMISE_STATUS_PENDING) return;
                    this.status = PROMISE_STATUS_FULFILLED;
                    this.value = value;
                    // console.log('resolve被调用', this.value);
                    // * 执行then传入进来的第一个回调函数
                    this.onResolvedFns.forEach(Fn => {
                        Fn(this.value);
                    });
                });
            }
        };
        const reject = reason => {
            if (this.status == PROMISE_STATUS_PENDING) {
                //  * 添加微任务
                queueMicrotask(() => {
                    if (this.status !== PROMISE_STATUS_PENDING) return;
                    this.status = PROMISE_STATUS_REJECTED;
                    this.reason = reason;
                    // console.log('reject被调用', this.reason);
                    // * 执行then传入进来的第二个回调函数
                    this.onRejectedFns.forEach(Fn => {
                        Fn(this.reason);
                    });
                });
            }
        };
        // * 在调用executor时判断里面是否抛出异常
        try {
            executor(resolve, reject);
        } catch (err) {
            reject(err);
        }
    }
    // then方法
    then(onResolved, onRejected) {
        onRejected =
            onRejected ||
            (err => {
                throw err;
            });
        return new myPromise((resolve, reject) => {
            // 如果then方法调用的时候,状态已经确定下来了,应该直接执行的
            if (this.status === PROMISE_STATUS_FULFILLED && onResolved) {
                // onResolved(this.value);
                execFunctionWithCatchError(onResolved, this.value, resolve, reject);
            } else if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
                // onRejected(this.reason);
                execFunctionWithCatchError(
                    onRejected,
                    this.reason,
                    resolve,
                    reject,
                );
            } else {
                // 将成功回调和失败回调添加到数组中
                if (onResolved)
                    this.onResolvedFns.push(() => {
                        execFunctionWithCatchError(
                            onResolved,
                            this.value,
                            resolve,
                            reject,
                        );
                    });
                if (onRejected)
                    this.onRejectedFns.push(() => {
                        execFunctionWithCatchError(
                            onRejected,
                            this.reason,
                            resolve,
                            reject,
                        );
                    });
            }
        });
    }
    // * catch方法
    catch(onRejected) {
        this.then(undefined, onRejected);
    }
    // finally方法
    finally(onFinally) {
        return this.then(
            () => {
                onFinally();
            },
            () => {
                onFinally();
            },
        );
    }
    // 类方法resolve
    static resolve(value) {
        return new myPromise((resolve, reject) => {
            resolve(value);
        });
    }
    // 类方法reject
    static reject(reason) {
        return new myPromise((resolve, reject) => {
            reject(reason);
        });
    }
    // 类方法all
    static all(promises) {
        // * 问题关键:什么时候执行resolve,什么时候执行reject
        return new myPromise((resolve, reject) => {
            let values = [];
            promises.forEach(promise => {
                promise
                    .then(res => {
                        values.push(res);
                        if (values.length == promises.length) resolve(values);
                    })
                    .catch(err => {
                        reject(err);
                    });
            });
        });
    }
    // 类方法allSettled
    static allSettled(promises) {
        return new myPromise((resolve, reject) => {
            let results = [];
            promises.forEach(promise => {
                promise
                    .then(res => {
                        results.push({ status: PROMISE_STATUS_FULFILLED, value: res });
                        if (results.length == promises.length) resolve(results);
                    })
                    .catch(err => {
                        results.push({ status: PROMISE_STATUS_REJECTED, value: err });
                        if (results.length == promises.length) resolve(results);
                    });
            });
        });
    }
    // 类方法race
    static race(promises) {
        return new myPromise((resolve, reject) => {
            promises.forEach(promise => {
                // promise.then(res=>{
                //  resolve(res);
                // }).catch(err=>{
                //  reject(err);
                // })
                promise.then(resolve, reject);
            });
        });
    }
    // 类方法any
    static any(promises) {
        // * resolve 必须等待有一个成功的结果
        // * reject 所有的都失败才执行 reject
        return new myPromise((resolve, reject) => {
            let reasons = [];
            promises.forEach(promise => {
                promise
                    .then(res => {
                        resolve(res);
                    })
                    .catch(err => {
                        reasons.push(err);
                        if (reasons.length == promises.length) {
                            reject(
                                new AggregateError(
                                    reasons,
                                    ' AggregateError: All promises were rejected',
                                ),
                            );
                        }
                    });
            });
        });
    }
}

说了这么多,最后放上一张Promise的知识点关系图作为结束。

promise.png

参考文献:https://www.jianshu.com/p/e91ce318d7ad

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,311评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,339评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,671评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,252评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,253评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,031评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,340评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,973评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,466评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,937评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,039评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,701评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,254评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,259评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,497评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,786评论 2 345

推荐阅读更多精彩内容