【JS手写系列】手写实现Promise

1,110 阅读13分钟

靡不有初,鲜克有终

不积跬步无以至千里

0、前言

  • 大多数时候,我们在处理异步操作问题都是直接使用Promise加上它的附属API(then、catch、all、race),或者使用更简洁的async/await,关于它们的具体实现原理可能就不太熟悉了;
  • 这篇文章旨在以简洁、清晰的思路,自己动手实现一个Promise,相信看完之后,在你的脑袋里面会形成一张结构图,可以用于面试装X了,毕竟会用和会实现是两种级别的事情;
  • 然后,就可以大胆践行我们的面试总指导方针:📢📢📢 唬住了要30k,没唬住要3k

图片.png

本文主要是记录自己的手写Promise过程,在逐步深入阶段参考了很多的文章,其中这两个资源参考较多,强烈推荐👍:

掘金:手把手一行一行代码教你“手写Promise“

B站:手写Promise核心代码 - JavaScript前端Web工程师

另外,为了大家的阅读更加直观,文章中会用以下符号进行标注:

🟢 代表手写的实现步骤

❓ 代表出现的问题描述

📌 代表问题的解决更新

1、快速感知

  • 关于异步操作传统方案是单纯使用回调函数,如果依赖过深,就会出现回调地狱问题

    • 看个🌰:
      // 场景需求:依次读取1、2、3.txt文件的值
      const fs = require('fs');
      ​
      fs.readFile('./1.txt', 'utf8', (err, result1) => {
        console.log(result1)
        fs.readFile('./2.txt', 'utf8', (err, result2) => {
          console.log(result2)
          fs.readFile('./3.txt', 'utf8', (err, result3) => {
            console.log(result3)
          })
        })
      });
      
  • Promise 是一门新的技术(ES6 规范正式纳入,2017年)

  • PromiseJS 中进行异步编程的新解决方案

1.1、涉及知识点

1.2、Promise核心要点

  • 一个 Promise 必然处于以下几种状态之一 👇:

    • 待定 (pending): 初始状态,既没有被兑现,也没有被拒绝
    • 已成功 (resolved/fulfilled): 意味着操作成功完成
    • 已拒绝 (rejected): 意味着操作失败
  • 四个知识点 👇:

    • 执行了resolve()Promise状态会变成resolved/fulfilled,即 已完成状态

    • 执行了reject()Promise状态会变成rejected,即 被拒绝状态

    • promise的状态只可能从“等待”转到“完成”态或者“拒绝”态,不能逆向转换

      • 且状态只能改变一次,即改变之后无论变为成功还是失败, 都不会再改变
    • Promise中有throw的话,就相当于执行了reject()

  • 基础使用Demo👇:

    • const p = new Promise((resolve, reject) => {
          setTimeout(() => {
              const time = Date.now()
              // 奇数代表成功
              if (time % 2 === 1) {
                  resolve('成功的值 ' + time)
              } else {
                  reject('失败的值' + time)
              }
          }, 2000)
      })
      ​
      p.then((value) => {
          console.log('成功的 value: ', value)
      }).catch((reason) => {
          console.log('失败的 reason: ', reason)
      })
      

2、直入佳境

2.1、定义初始类结构

原生的promise我们一般都会用new来创建实例 👇 :

let promise = new Promise()

🟢首先,创建一个myPromise类。

class myPromise {}

new一个promise实例的时候肯定是需要传入参数的,不然这个实例用处不大;

let promise = new Promise(() => {})
  • constructor()是类的默认方法,通过new命令生成对象实例时,自动调用该方法
  • 一个类必须有constructor()方法,如果没有显式定义,一个空的constructor()方法会被默认添加

🟢在类中写上构造函数constructor,并且里面添加一个参数,执行一下。

class myPromise {
    constructor(func) {
        func();
    }
}
// 此处的func相当于 new Promise((resolve, reject) => {}) 中的 (resolve, reject) => {}

2.2、实现 resolve 和 reject

2.2.1、管理状态和结果

🟢为func函数参数传入它自己的函数,也就是resolve()reject()

class myPromise {
    constructor(func) {
        func(this.resolve, this.reject)
    }
    resolve (result) {}
    reject (reason) {}
}

❓ 那么这里的resolve()reject()方法应该如何执行呢?里面应该写什么内容呢?

这就需要用到状态了 👇

🟢增加状态值,定义初始值为pendingresolve()、reject()中对状态进行修改。

class myPromise {
    static PENDING = 'pending';
    static FULFILLED = 'fulfilled';
    static REJECTED = 'rejected';
​
    constructor(func) {
        this.status = myPromise.PENDING
        func(this.resolve, this.reject)
    }
​
    resolve () {
        if (this.status === myPromise.PENDING) {
            this.status = myPromise.FULFILLED;
        }
    }
​
    reject () {
        if (this.status === myPromise.PENDING) {
            this.status = myPromise.REJECTED;
        }
    }
}

到这里之后,我们可以回想一下我们的基础Demo中关于原生Promise的使用👇

// 奇数代表成功
if (time % 2 === 1) {
    resolve('成功的值 ' + time)
} else {
    reject('失败的值' + time)
}

可以看到resolve()、reject()是支持参数传递的,话不多说👇

2.2.2、this指向问题

🟢resolve()、reject()支持参数传递

class myPromise {
    static PENDING = 'pending';
    static FULFILLED = 'fulfilled';
    static REJECTED = 'rejected';
​
    constructor(func) {
        this.status = myPromise.PENDING
+       this.result = null
        func(this.resolve, this.reject)
    }
​
    resolve (result) {
        if (this.status === myPromise.PENDING) {
            this.status = myPromise.FULFILLED;
+           this.result = result
        }
    }
​
    reject (reason) {
        if (this.status === myPromise.PENDING) {
            this.status = myPromise.REJECTED;
+           this.result = reason
        }
    }
}

目前看起来还是挺愉快无阻的,我们来测试一下:

const p = new myPromise((resolve, reject) => {
    resolve('正常结果')
})

得到:

Uncaught TypeError: Cannot read properties of undefined (reading 'status')

❓这是什么情况,status怎么了?

status属性我们已经创建了,不应该是undefined, 但resolve()reject()方法里调用的status 前面是有this关键字的,那么只有一种可能🧐,调用this.status的时候并没有调用constructor里的this.status,也就是这里的this已经跟丢了👇

constructor(func) {
+   console.log(this); // 得到 实例对象
    this.status = myPromise.PENDING
    this.result = null
    func(this.resolve, this.reject)
}
​
resolve(result) {
+   console.log(this); // 得到 undefined
➡  if (this.status === myPromise.PENDING) {
➡  this.status = myPromise.FULFILLED;
    this.result = result;
  }
}
​
reject(reason) {
➡  if (this.status === myPromise.PENDING) {
➡  this.status = myPromise.REJECT;
    this.result = reason;
  }
}

我们在new一个新实例的时候执行的是constructor里的内容,也就是constructor里的this确实是新实例的,但现在我们是在新实例被创建后再在外部环境下执行resolve()方法的,这里的resolve()看着像是和实例一起执行的,其实不然,也就相当于不在class内部使用这个this,而我们没有在外部定义任何status变量,因此这里会报错

解决classthis指向问题一般会用箭头函数,bind或者proxy,这个问题也欢迎大家查看我的另一篇文章:【JS手写系列】手写实现call、apply、bind

在这里我们就可以使用bind来绑定this,只需要在构造函数constructor中的this.resolvethis.reject后加上,.bind(this)就可以了 😺:

📌

给实例的 resolve()reject()方法绑定this为当前的实例对象

class myPromise {
    static PENDING = 'pending';
    static FULFILLED = 'fulfilled';
    static REJECTED = 'rejected';
​
    constructor(func) {
        this.status = myPromise.PENDING
        this.result = null
+       func(this.resolve.bind(this), this.reject.bind(this))
    }
​
    resolve (result) {
        if (this.status === myPromise.PENDING) {
            this.status = myPromise.FULFILLED;
            this.result = result
        }
    }
​
    reject (reason) {
        if (this.status === myPromise.PENDING) {
            this.status = myPromise.REJECTED;
            this.result = reason
        }
    }
}

2.3、实现 then 方法

2.3.1、基础then

then方法可以传入两个参数,这两个参数都是函数,一个是当状态为fulfilled 成功 时执

行的代码,另一个是当状态为 rejected 拒绝 时执行的代码,虽然可能一直只用一个函数参

数,但不要忘记这里是两个函数参数🧐,看个原生then的🌰:

let promise = new Promise((resolve, reject) => {
    resolve('这次一定')
})
​
promise.then(
 result => {
   console.log(result);
 },
 reason => {
   console.log(reason.message);
 }
)

因此我们就可以先给手写的then里面添加 两个参数

  • 一个是 onFulfilled 表示 “当状态为成功时”
  • 另一个是 onRejected 表示 “当状态为拒绝时”
class myPromise {
    static PENDING = 'pending';
    static FULFILLED = 'fulfilled';
    static REJECTED = 'rejected';
​
    constructor(func) {
        this.status = myPromise.PENDING
        this.result = null
        func(this.resolve.bind(this), this.reject.bind(this))
    }
​
    resolve (result) {
        if (this.status === myPromise.PENDING) {
            this.status = myPromise.FULFILLED;
            this.result = result
        }
    }
​
    reject (reason) {
        if (this.status === myPromise.PENDING) {
            this.status = myPromise.REJECTED;
            this.result = reason
        }
    }
​
    then (onResolve, onReject) { 
        if (this.status === myPromise.FULFILLED) {
            onResolve(this.result)
        }
​
        if (this.status === myPromise.REJECTED) {
            onReject(this.result)
        }
    }
}

完成then的基础版本~

2.3.2、坑一:直接抛出异常

❓ 直接再回调函数中抛出错误会怎么样?

const p = new myPromise((resolve, reject) => {
    throw new Error('直接抛出错误')
})

得到:(注意是未捕获状态)

Uncaught Error: 直接抛出错误

📌所以我们需要再构造函数中进行try catch处理👇

(注意catch里面的reject不用绑定this,因为这里只需要直接抛出错误信息就行)

class myPromise {
    static PENDING = 'pending';
    static FULFILLED = 'fulfilled';
    static REJECTED = 'rejected';
​
    constructor(func) {
        this.status = myPromise.PENDING
        this.result = null
​
        try {
            func(this.resolve.bind(this), this.reject.bind(this))
        } catch (error) {
            this.reject(error)
        }
    }
​
    resolve (result) {
        if (this.status === myPromise.PENDING) {
            this.status = myPromise.FULFILLED;
            this.result = result
        }
    }
​
    reject (reason) {
        if (this.status === myPromise.PENDING) {
            this.status = myPromise.REJECTED;
            this.result = reason
        }
    }
​
    then (onResolve, onReject) {
        if (this.status === myPromise.FULFILLED) {
            onResolve(this.result)
        }
​
        if (this.status === myPromise.REJECTED) {
            onReject(this.result)
        }
    }
}
​
const p = new myPromise((resolve, reject) => {
    throw new Error('直接抛出错误')
})
​
p.then(
    (result) => { console.log(result) },
    (reason) => { console.log(reason.message) }
)

2.3.3、坑二:then中两个参数必须是函数

原生Promise规定then中两个参数必须是函数,传其它的会直接报错,有兴趣的

const p = new myPromise((resolve, reject) => {
    resolve('then的参数不全是函数')
})
​
p.then(
    undefined,
    (reason) => { console.log(reason.message) }
)

得到:

Uncaught TypeError: onResolve is not a function

📌对传参是否为函数进行判定和处理

class myPromise {
    static PENDING = 'pending';
    static FULFILLED = 'fulfilled';
    static REJECTED = 'rejected';
​
    constructor(func) {
        this.status = myPromise.PENDING
        this.result = null
​
        try {
            func(this.resolve.bind(this), this.reject.bind(this))
        } catch (error) {
            this.reject(error)
        }
    }
​
    resolve (result) {
        if (this.status === myPromise.PENDING) {
            this.status = myPromise.FULFILLED;
            this.result = result
        }
    }
​
    reject (reason) {
        if (this.status === myPromise.PENDING) {
            this.status = myPromise.REJECTED;
            this.result = reason
        }
    }
​
    then (onResolve, onReject) {
+       onResolve = typeof onResolve === 'function' ? onResolve : () => { }
+       onReject = typeof onReject === 'function' ? onReject : () => { }
​
        if (this.status === myPromise.FULFILLED) {
            onResolve(this.result)
        }
​
        if (this.status === myPromise.REJECTED) {
            onReject(this.result)
        }
    }
}
​
const p = new myPromise((resolve, reject) => {
    resolve('then的参数不全是函数,也不会有问题了')
})
​
p.then(
    undefined,
    (reason) => { console.log(reason.message) }
)

2.4、异步处理

2.4.1、坑一:then本身未进行异步处理

走个测试👇

console.log(111);
const p = new myPromise((resolve, reject) => {
    console.log(222);
    resolve('正常结果')
})
​
p.then(
    (result) => { console.log(result) },
    (reason) => { console.log(reason.message) }
)
console.log(333);

得到:

图片.png

可以看到是直接输出的同步执行结果...

📌没啥好说的,给then里面主动添加异步就行,这里采用宏任务,也可以使用微任务处理

class myPromise {
    static PENDING = 'pending';
    static FULFILLED = 'fulfilled';
    static REJECTED = 'rejected';
​
    constructor(func) {
        this.status = myPromise.PENDING
        this.result = null
​
        try {
            func(this.resolve.bind(this), this.reject.bind(this))
        } catch (error) {
            this.reject(error)
        }
    }
​
    resolve (result) {
        if (this.status === myPromise.PENDING) {
            this.status = myPromise.FULFILLED;
            this.result = result
        }
    }
​
    reject (reason) {
        if (this.status === myPromise.PENDING) {
            this.status = myPromise.REJECTED;
            this.result = reason
        }
    }
​
    then (onResolve, onReject) {
        onResolve = typeof onResolve === 'function' ? onResolve : () => { }
        onReject = typeof onReject === 'function' ? onReject : () => { }
​
        if (this.status === myPromise.FULFILLED) {
+           setTimeout(() => {
                onResolve(this.result)
            });
        }
​
        if (this.status === myPromise.REJECTED) {
+           setTimeout(() => {
                onReject(this.result)
            });
        }
    }
}
​
console.log(111);
const p = new myPromise((resolve, reject) => {
    console.log(222);
    resolve('正常结果')
})
​
p.then(
    (result) => { console.log(result) },
    (reason) => { console.log(reason.message) }
)
console.log(333);

2.4.2、坑二:实例化的时候进行异步调用

console.log(111);
const p = new myPromise((resolve, reject) => {
    console.log(222);
​
    setTimeout(() => {
        resolve('正常结果')
        console.log(444);
    });
})
​
p.then(
    (result) => { console.log(result) },
    (reason) => { console.log(reason.message) }
)
console.log(333);

❓可以发现正常结果几个字并未输出...

这又是为什么呢?通过分析我们知道了,是因为先执行了then方法,但发现这个时候状态依旧是 pending,而我们手写部分没有定义pending待定状态的时候应该做什么,因此就少了正常结果 这句话的输出。

对微、宏任务、事件循环机制理解不是很到位的朋友👉:JS的事件执行机制

📌所以我们就 直接给then方法里面添加待定状态的情况就可以了,也就是用if进行判断:

class myPromise {
    ...
    then (onResolve, onReject) {
        onResolve = typeof onResolve === 'function' ? onResolve : () => { }
        onReject = typeof onReject === 'function' ? onReject : () => { }
​
        if (this.PromiseState === myPromise.PENDING) {
           ...
        }
​
        if (this.status === myPromise.FULFILLED) {
            setTimeout(() => {
                onResolve(this.result)
            });
        }
​
        if (this.status === myPromise.REJECTED) {
            setTimeout(() => {
                onReject(this.result)
            });
        }
    }
}

但是问题来了,当then里面判断到 pending 待定状态时我们要干什么?

因为这个时候resolve或者reject还没获取到任何值,因此我们必须让then里的函数稍后再执行,等resolve执行了以后,再执行then

为了保留then里的函数,我们可以创建 数组保存函数

为什么用 数组 来保存这些回调呢?因为一个promise实例可能会多次 then,也就是经典的 链式调用,而且数组是先入先出的顺序

在实例化对象的时候就让每个实例都有这两个数组:

  • onFulfilledCallbacks :用来 保存成功回调
  • onRejectedCallbacks :用来 保存失败回调
class myPromise {
    static PENDING = 'pending';
    static FULFILLED = 'fulfilled';
    static REJECTED = 'rejected';
    constructor(func) {
        this.PromiseState = myPromise.PENDING;
        this.PromiseResult = null;
+       this.onFulfilledCallbacks = []; // 保存成功回调
+       this.onRejectedCallbacks = []; // 保存失败回调
        try {
            func(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
            this.reject(error)
        }
    }
}

◾ 接着就完善then里面的代码,也就是当判断到状态为 pending 待定时,暂时保存两个回调,也就是说暂且把then里的两个函数参数分别放在两个数组里面:

class myPromise {
    ...
    then (onResolve, onReject) {
        onResolve = typeof onResolve === 'function' ? onResolve : () => { }
        onReject = typeof onReject === 'function' ? onReject : () => { }
​
        if (this.status === myPromise.PENDING) {
+          this.onFulfilledCallbacks.push(onResolve);
+           this.onRejectedCallbacks.push(onRejected);
        }
​
        if (this.status === myPromise.FULFILLED) {
            setTimeout(() => {
                onResolve(this.result)
            });
        }
​
        if (this.status === myPromise.REJECTED) {
            setTimeout(() => {
                onReject(this.result)
            });
        }
    }
}

数组里面放完函数以后,就可以完善resolvereject的代码了

在执行resolve或者reject的时候,遍历自身的callbacks数组,看看数组里面有没有then那边 保留 过来的 待执行函数然后逐个执行数组里面的函数,执行的时候会传入相应的参数:

class myPromise {
    ...
    resolve (result) {
        if (this.status === myPromise.PENDING) {
            this.status = myPromise.FULFILLED;
            this.result = result
            this.resolveCallbacks.forEach(callback => callback(result))
        }
    }
​
    reject (reason) {
        if (this.status === myPromise.PENDING) {
            this.status = myPromise.REJECTED;
            this.result = reason
            this.rejectCallbacks.forEach(callback => callback(reason))
        }
    }
}

可以测试一下,现在正常结果几个字确实是输出了,但是顺序还是不太对...

这里有一个很多人忽略的小细节,resolve()reject()是要在事件循环末尾执行的,所以:

class myPromise {
    ...
    resolve (result) {
+       setTimeout(() => {
            if (this.status === myPromise.PENDING) {
                this.status = myPromise.FULFILLED;
                this.result = result
                this.resolveCallbacks.forEach(callback => callback(result))
            }
        });
    }
​
    reject (reason) {
+       setTimeout(() => {
            if (this.status === myPromise.PENDING) {
                this.status = myPromise.REJECTED;
                this.result = reason
                this.rejectCallbacks.forEach(callback => callback(reason))
            }
        });
    }
}

此问题完美收官!

2.5、then的链式调用

📌这个问题没那么简单,具体详情可参考手把手一行一行代码教你“手写Promise“

class myPromise {
    ...
    then (onResolved, onRejected) {
        let promise2 = new myPromise((resolve, reject) => {
            if (this.status === myPromise.PENDING) {
                this.resolveCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            if (typeof onResolved !== 'function') {
                                resolve(this.result);
                            } else {
                                let x = onResolved(this.result);
                                resolvePromise(promise2, x, resolve, reject);
                            }
                        } catch (e) {
                            reject(e);
                        }
                    });
                });

                this.rejectCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            if (typeof onRejected !== 'function') {
                                reject(this.result);
                            } else {
                                let x = onRejected(this.result);
                                resolvePromise(promise2, x, resolve, reject);
                            }
                        } catch (e) {
                            reject(e);
                        }
                    });
                });
            }

            if (this.status === myPromise.FULFILLED) {
                setTimeout(() => {
                    try {
                        if (typeof onResolved !== 'function') {
                            resolve(this.result);
                        } else {
                            let x = onResolved(this.result);
                            resolvePromise(promise2, x, resolve, reject);
                        }
                    } catch (e) {
                        reject(e);
                    }
                });
            }

            if (this.status === myPromise.REJECTED) {
                setTimeout(() => {
                    try {
                        if (typeof onRejected !== 'function') {
                            reject(this.result);
                        } else {
                            let x = onRejected(this.result);
                            resolvePromise(promise2, x, resolve, reject);
                        }
                    } catch (e) {
                        reject(e)
                    }
                });
            }
        })

        return promise2
    }
}

function resolvePromise (promise2, x, resolve, reject) {
    if (x === promise2) {
        throw new TypeError('Chaining cycle detected for promise');
    }

    if (x instanceof myPromise) {
        x.then(y => {
            resolvePromise(promise2, y, resolve, reject)
        }, reject);
    } else if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))) {
        try {
            var then = x.then;
        } catch (e) {
            return reject(e);
        }

        if (typeof then === 'function') {
            let called = false;
            try {
                then.call(
                    x,
                    y => {
                        if (called) return;
                        called = true;
                        resolvePromise(promise2, y, resolve, reject);
                    },
                    r => {
                        if (called) return;
                        called = true;
                        reject(r);
                    }
                )
            } catch (e) {
                if (called) return;
                called = true;
                reject(e);
            }
        } else {
            resolve(x);
        }
    } else {
        return resolve(x);
    }
}

2.6、all和race

先来看一个🌰:

function test () {
    return new Promise(resolve => {
        setTimeout(() => {
            console.log('test');
            resolve('resolve的test')
        }, 2000)
    })
}
function test1 () {
    return new Promise(resolve => {
        setTimeout(() => {
            console.log('test1');
            resolve('resolve的test1')
        }, 2000)
    })
}
function test2 () {
    return new Promise(resolve => {
        setTimeout(() => {
            console.log('test2');
            resolve('resolve的test2')
        }, 2000)
    })
}
​
async function call () {
    await test()
    await test1()
    await test2()
}
call()  

因为await继发执行,上面代码的执行时间大概需要花6000ms...

话不多说👇

2.6.1、all

  • 接收一个Promise数组,数组中如有非Promise项,则此项当做成功
  • 如果所有Promise都成功,则返回成功结果数组
  • 如果有一个Promise失败,则返回这个失败结果
class myPromise {
    ...
    all (paramsArr) {
        const result = []
        let count = 0
        return new myPromise((resolve, reject) => {
            paramsArr.forEach((item, index) => {
                if (item instanceof myPromise) {
                    item.then(
                        res => {
                            count++
                            result[index] = res
                            count === paramsArr.length && resolve(result)
                        },
                        err => reject(err)
                    )
                } else {
                    count++
                    result[index] = item
                    count === paramsArr.length && resolve(result)
                }
            })
        })
    }
}

2.6.2、race

  • 接收一个Promise数组,数组中如有非Promise项,则此项当做成功
  • 哪个Promise最快得到结果,就返回那个结果,无论成功失败
class myPromise {
    ...
    race (paramsArr) {
        return new myPromise((resolve, reject) => {
            paramsArr.forEach(item => {
                if (item instanceof myPromise) {
                    item.then(res => {
                        resolve(res)
                    }, err => {
                        reject(err)
                    })
                } else {
                    resolve(item)
                }
            })
        })
    }
}

2.6.3、再测试

const p = new myPromise((resolve, reject) => {})
​
function call () {
    p.all([test(), test1(), test2()]).then((values) => {
        console.log(values);
    });
​
    p.race([test(), test1(), test2()]).then((values) => {
        console.log(values);
    });
}
call()

✔,测试可以看出大概耗时2000ms并发执行

3、完整代码

class myPromise {
    static PENDING = 'pending';
    static FULFILLED = 'fulfilled';
    static REJECTED = 'rejected';

    constructor(func) {
        this.status = myPromise.PENDING
        this.result = null
        this.resolveCallbacks = []
        this.rejectCallbacks = []
        try {
            func(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
            this.reject(error)
        }
    }
    resolve (result) {
        setTimeout(() => {
            if (this.status === myPromise.PENDING) {
                this.status = myPromise.FULFILLED;
                this.result = result
                this.resolveCallbacks.forEach(callback => callback(result))
            }
        });
    }
    reject (reason) {
        setTimeout(() => {
            if (this.status === myPromise.PENDING) {
                this.status = myPromise.REJECTED;
                this.result = reason
                this.rejectCallbacks.forEach(callback => callback(reason))
            }
        });
    }
    then (onResolved, onRejected) {
        let promise2 = new myPromise((resolve, reject) => {
            if (this.status === myPromise.PENDING) {
                this.resolveCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            if (typeof onResolved !== 'function') {
                                resolve(this.result);
                            } else {
                                let x = onResolved(this.result);
                                resolvePromise(promise2, x, resolve, reject);
                            }
                        } catch (e) {
                            reject(e);
                        }
                    });
                });
                this.rejectCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            if (typeof onRejected !== 'function') {
                                reject(this.result);
                            } else {
                                let x = onRejected(this.result);
                                resolvePromise(promise2, x, resolve, reject);
                            }
                        } catch (e) {
                            reject(e);
                        }
                    });
                });
            }

            if (this.status === myPromise.FULFILLED) {
                setTimeout(() => {
                    try {
                        if (typeof onResolved !== 'function') {
                            resolve(this.result);
                        } else {
                            let x = onResolved(this.result);
                            resolvePromise(promise2, x, resolve, reject);
                        }
                    } catch (e) {
                        reject(e);
                    }
                });
            }

            if (this.status === myPromise.REJECTED) {
                setTimeout(() => {
                    try {
                        if (typeof onRejected !== 'function') {
                            reject(this.result);
                        } else {
                            let x = onRejected(this.result);
                            resolvePromise(promise2, x, resolve, reject);
                        }
                    } catch (e) {
                        reject(e)
                    }
                });
            }
        })


        return promise2
    }

    all (paramsArr) {
        const result = []
        let count = 0
        return new myPromise((resolve, reject) => {
            paramsArr.forEach((item, index) => {
                if (item instanceof myPromise) {
                    item.then(
                        res => {
                            count++
                            result[index] = res
                            count === paramsArr.length && resolve(result)
                        },
                        err => reject(err)
                    )
                } else {
                    count++
                    result[index] = item
                    count === paramsArr.length && resolve(result)
                }
            })
        })
    }
    race (paramsArr) {
        return new myPromise((resolve, reject) => {
            paramsArr.forEach(item => {
                if (item instanceof myPromise) {
                    item.then(res => {
                        resolve(res)
                    }, err => {
                        reject(err)
                    })
                } else {
                    resolve(item)
                }
            })
        })
    }
}

function resolvePromise (promise2, x, resolve, reject) {
    if (x === promise2) {
        throw new TypeError('Chaining cycle detected for promise');
    }

    if (x instanceof myPromise) {
        x.then(y => {
            resolvePromise(promise2, y, resolve, reject)
        }, reject);
    } else if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))) {
        try {
            var then = x.then;
        } catch (e) {
            return reject(e);
        }

        if (typeof then === 'function') {
            let called = false;
            try {
                then.call(
                    x,
                    y => {
                        if (called) return;
                        called = true;
                        resolvePromise(promise2, y, resolve, reject);
                    },
                    r => {
                        if (called) return;
                        called = true;
                        reject(r);
                    }
                )
            } catch (e) {
                if (called) return;
                called = true;

                reject(e);
            }
        } else {
            resolve(x);
        }
    } else {
        return resolve(x);
    }
}

4、最后

本文主要是记录自己的手写Promise过程,在逐步深入阶段参考了很多的文章,其中这两个资源参考较多,强烈推荐👍:

掘金:手把手一行一行代码教你“手写Promise“

B站:手写Promise核心代码 - JavaScript前端Web工程师

其它优质参考链接👇:

码字不易,欢迎点赞🚀🚀🚀