手写Promise实现

97 阅读4分钟

1.Promise解决回调地狱:
(1)回调函数延迟绑定:回调函数不是直接声明的,而是在通过后面的 then 方法传入的,即延迟传入。
(2)返回值穿透:异步方法并不会立即返回最终的值,而是会返回一个promise,后面可以依次完成链式调用。
(3)错误冒泡:前面产生的错误会一直向后传递,直到被 catch 接收到。

image.png

一.简易版实现

// 三大状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

function myPromise(executor){
    let self = this; //缓存当前Promise实例
    self.status = PENDING; //当前状态
    self.value = undefined; //成功传回的值
    self.reason = undefined; //失败的原因
    self.onFulfilled = undefined; //成功的回调
    self.onRejected = undefined; //失败的回调

    let resolve = (value)=>{
        if (self.status === PENDING){
            setTimeout(()=>{
                self.status = FULFILLED;
                self.value = value;
                self.onFulfilled(self.value);//resolve时执行成功的回调。
            },0)

        }
    }

    let reject = (reason) =>{
        if (self.status === PENDING){
            setTimeout(()=>{
                self.status = REJECTED;
                self.reason = reason;
                self.onRejected(self.reason);

            },0)
        }
    }

    // 如果exector执行报错,则直接执行reject
    try{
        executor(resolve,reject);
    }catch(err){
        reject(err);
    }
}

myPromise.prototype.then = function(onFulfilled,onRejected){
    if (this.status === PENDING){
        this.onFulfilled = onFulfilled;
        this.onRejected = onRejected;
    }
    if (this.status === FULFILLED){
        // 如果状态时fulfilled,直接执行成功回调,并将成功的值传入
        onFulfilled(this.value);
    }
    if (this.status === REJECTED){
        // 如果状态时rejected,直接执行失败的回调,并将失败原因传入
        onRejected(this.reason);
    }
}

二.设置成回调数组

将回调函数处设置为数组:

self.onFulfilledCallbacks = [];
self.onRejectedCallbacks = [];

then函数中,当状态为PENDING时,将回调函数加入到数组中

if (this.status === PENDING) {
    this.onFulfilledCallbacks.push(onFulfilled);
    this.onRejectedCallbacks.push(onRejected);

在resolve和reject中对回调函数的执行进行部分修改:

// resolve 中
self.onFulfilledCallbacks.forEach((callback) => callback(self.value));
//reject 中
self.onRejectedCallbacks.forEach((callback) => callback(self.error));

全部代码如下:

// 三大状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

function myPromise(executor){
    let self = this; //缓存当前Promise实例
    self.status = PENDING; //当前状态
    self.value = undefined; //成功传回的值
    self.reason = undefined; //失败的原因
    self.onFulfilledCallbacks = []; //成功的回调
    self.onRejectedCallbacks = []; //失败的回调

    let resolve = (value)=>{
        if (self.status === PENDING){
            setTimeout(()=>{
                self.status = FULFILLED;
                self.value = value;
                self.onFulfilledCallbacks.forEach((callback)=>{callback(this.value)});//resolve时依次执行成功的回调。
            },0)
        }
    }

    let reject = (reason) =>{
        if (self.status === PENDING){
            setTimeout(()=>{
                self.status = REJECTED;
                self.reason = reason;
                self.onRejectedCallbacks((callback)=>{callback(self.reason)});
            },0)
        }
    }

    // 如果exector执行报错,则直接执行reject
    try{
        executor(resolve,reject);
    }catch(err){
        reject(err);
    }
}

myPromise.prototype.then = function(onFulfilled,onRejected){
    if (this.status === PENDING){
        this.onFulfilledCallbacks.push(onFulfilled);
        this.onRejectedCallbacks.push(onRejected);
    }
    if (this.status === FULFILLED){
        // 如果状态时fulfilled,直接执行成功回调,并将成功的值传入
        onFulfilled(this.value);
    }
    if (this.status === REJECTED){
        // 如果状态时rejected,直接执行失败的回调,并将失败原因传入
        onRejected(this.reason);
    }
    return this;
}

三.解决链式调用

解决链式调用:
1、若为链式调用,我们默认在第一个then里返回的是一个promise。
•若返回的是promise则传递到下一个then中。
•如果返回一个普通的值,则将普通的值传递给下一个then中。
2、当我们在第一个then中 return 了一个参数(参数未知,需判断)。这个return出来的新的promise就是onFulfilled()或onRejected()的值

秘籍则规定onFulfilled()或onRejected()的值,即第一个then返回的值,叫做x,判断x的函数叫做resolvePromise

// 三大状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

function myPromise(executor) {
    let self = this; //缓存当前myPromise实例
    self.status = PENDING; //当前状态
    self.value = undefined; //成功传回的值
    self.reason = undefined; //失败的原因
    self.onFulfilledCallbacks = []; //成功的回调
    self.onRejectedCallbacks = []; //失败的回调

    let resolve = (value) => {
        if (self.status === PENDING) {
            setTimeout(() => {
                self.status = FULFILLED;
                self.value = value;
                self.onFulfilledCallbacks.forEach((callback) => { callback(this.value) });//resolve时依次执行成功的回调。
            }, 0)

        }
    }

    let reject = (reason) => {
        if (self.status === PENDING) {
            setTimeout(() => {
                self.status = REJECTED;
                self.reason = reason;
                self.onRejectedCallbacks.forEach((callback) => { callback(self.reason) });

            }, 0)
        }
    }

    // 如果exector执行报错,则直接执行reject
    try {
        executor(resolve, reject);
    } catch (err) {
        reject(err);
    }
}

myPromise.prototype.then = function (onFulfilled, onRejected) {
    // onFulfilled, onRejected都是可选参数,如果他们不是函数,必须被忽略
    // • onFulfilled返回一个普通的值,成功时直接等于 value => value
    // • onRejected返回一个普通的值,失败时如果直接等于 value => value,则会跑到下一个then中的onFulfilled中,所以直接扔出一个错误 reason => throw err

    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

    let bridgemyPromise;
    let self = this;
    if (self.status === PENDING) {
        return bridgemyPromise = new myPromise((resolve, reject) => {
            self.onFulfilledCallbacks.push((value) => {
                setTimeout(() => {
                    try {
                        let x = onFulfilled(value);
                        resolvemyPromise(bridgemyPromise, x, resolve, reject);
                    } catch (reason) {
                        reject(reason);
                    }
                }, 0)
            });
            self.onRejectedCallbacks.push((reason) => {
                setTimeout(() => {
                    try {
                        let x = onRejected(reason);
                        resolvemyPromise(bridgemyPromise, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0)
            })
        })

    }
    if (this.status === FULFILLED) {
        // 如果状态时fulfilled,直接执行成功回调,并将成功的值传入
        return bridgemyPromise = new myPromise((resolve, reject) => {
            setTimeout(() => {
                try {
                    let x = onFulfilled(self.value);
                    resolvemyPromise(bridgemyPromise, x, resolve, reject);
                }
                catch (reason) {
                    reject(reason);
                }
            }, 0)

        })
    }
    if (this.status === REJECTED) {
        // 如果状态时rejected,直接执行失败的回调,并将失败原因传入
        return bridgemyPromise = new myPromise((resolve, reject) => {
            setTimeout(() => {
                try {
                    let x = onRejected(self.reason);
                    resolvemyPromise(bridgemyPromise, x, resolve, reject);
                }
                catch (reason) {
                    reject(reason);
                }
            })

        })
    }
    return bridgemyPromise;
}

其中一个重要的函数实现为:

// 兼容实现多种myPromise
function resolvemyPromise(bridgemyPromise, x, resolve, reject) {
    // 防止循环引用的问题
    if (bridgemyPromise === x) {
        return reject(new TypeError('Error'));
    }
    // called变量,用于判断是否已经调用过函数
    let called;
    // 判断x是否为对象或者函数,如果都不是,则将x传入resolve中
    if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
        try {
            // 如果x是对象或者函数的话,把x.then赋值给then,然后判断then的类型,如果不是函数类型的话,将x传入resolve中
            let then = x.then;
            // 如果then是函数,就默认是myPromise
            if (typeof then === 'function') {
                // 让then执行,第一个参数是this,后面是成功的回调和失败的回调
                then.call(x, y => {
                    if (called) return;
                    called = true;
                    resolvemyPromise(bridgemyPromise, x, resolve, reject);
                }, reason => {
                    if (called) return;
                    called = true;
                    reject(reason);
                })
            }
            else {
                resolve(x);
            }
        }
        catch (reason) {
            if (called) return;
            called = true;
            reject(reason);
        }
    }
    else {
        resolve(x);
    }

}

四.解决错误捕获及冒泡机制

Promise.prototype.catch = function (onRejected) {
  return this.then(null, onRejected);
}

五.catch和resolve、reject、race、all方法

文章借鉴: (1)developer.mozilla.org/zh-CN/docs/… (2)www.cnblogs.com/sugar-tomat… (3)juejin.cn/post/684490…