Promise实现原理

一、基础版 Promise

观察 Promise 表象

  1. Promise 需要使用 new 关键字实例化。
  2. Promise 首个参数是回调函数,且该回调函数是立即执行的。
  3. 执行器(回调函数)有两个参数,分别是 resolve 和 reject,在执行器内部可以通过括号调用。
  4. Promise 有三种状态,状态间存在规则且不可逆。
  5. resolve 和 reject 调用时改变 Promise 的状态。
  6. Promise then 方法 存在两个函数类型的参数,一个是成功时调用,一个是失败时调用。
  7. then 方法第一个回调函数参数是成功返回的结果值,该结果值为 resolve 调用时传入的值。第二个回调函数参数是失败返回的错误对象。

通过观察 Promise 表象得出的:需实现功能(和表象一一对应)

  1. Promise 是一个类。
  2. 通过new 实例化一个 Promise 类时,需要传递一个执行器(回调函数)进去,执行器会立即执行。
  3. 执行器有两个参数,参数类型皆是函数。
  4. Promise 有三个状态:pending、fulfilled、rejected,pending->fulfilled/pending->rejected,一旦状态确定就不可更改。
  5. 执行器参数函数调用时改变状态,resolve 和 reject 用来更改状态。
  6. 实现 then 方法,接受两个参数,参数类型为函数,Promise 状态更改为 fulfilled 时调用第一个参数,状态更改为 rejected 时调用第二个参数。
  7. resolve 接受一个值,在then 方法第一个回调函数执行时作为默认参数传入。reject 方法接收一个异常对象,在 then 方法第二个回调函数执行时作为默认参数传入。

Promise 基础实现

上述条件完成后我们基本可以实现一个基础 Promise 类。

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class PromiseM {
    status = PENDING;    // promise 状态
    value = undefined;   // 成功之后的值
    error = undefined;  // 失败后的原因
    constructor(fn) {
        return fn(this.resolve, this.reject);
    }
    resolve = (value) => {
        // 如果状态不是等待 组织程序向下执行
        if (this.status !== PENDING) return
        // 将状态更改为成功
        this.status = FULFILLED;
        // 保存成功后的值
        this.value = value;
    };
    reject = (error) => {
        // 如果状态不是等待 组织程序向下执行
        if (this.status !== PENDING) return
        // 将状态更改为失败
        this.status = REJECTED;
        // 保存失败后的原因
        this.error = error;
    };
    then = (successCallBack, failCallBack?) => {
        if (this.status === FULFILLED) {
            return successCallBack(this.value);
        }
        if (this.status === REJECTED) {
            return failCallBack(this.error);
        }
        throw false;
    }
}

我们可以如下调用实验是否完善:

const promiseM = new PromiseM((resolve, reject) => {
    resolve(1);
    // reject('fail')
}).then((res) => {
    console.log(res);
}, error => {
    console.log(error)
})

二、标准版 Promise

下面我们先阐述一些需要特殊补充的功能点,最后我们再把每一个功能点一一放出,最终再放上最终版代码。

1. Promise 异步处理

const promiseM = new PromiseM((resolve, reject) => {
    setTimeout(() => {
        resolve('成功');
    }, 2000)
}).then((res) => {
    console.log(res);
}, error => {
    console.log(error);
})

2. 一个 Promise 实例多次调用 then 方法(同步、异步都要考虑)

const promiseM = new PromiseM((resolve, reject) = {
    setTimeout(() => {
        resolve('success')
    }, 2000)
})

promiseM.then(res => {
    console.log(res);
}, error => {
    console.log(error)
})

promiseM.then(res => {
    console.log(res);
}, error => {
    console.log(error)
})

3. Promise then 链式调用、then 方法返回值

  • then 方法可以被链式调用。
  • then 方法会返回一个全新的 Promise 对象。
  • 后面 then 方法回调函数拿到的值是上一个 then 方法的返回值。
  • then 方法可以返回一个值或一个 Promise 对象。
promiseM.then(res => {
    return 1
}).then(res => {
    console.log(res)
})

4. 校验之避免循环调用

const m = promiseM.then(res => {
    return m
})

5. 错误处理

  • 执行器函数中出现错误时,触发 reject 并捕获异常
  • then 回调函数调用时出现错误,触发下一个 then 的 reject
  • then 回调函数的 REJECT status 的处理,以使 reject 状态下也可以达到链式调用,向下传递至下个 then
// 执行器 抛出异常
const promiseM = new PromiseM((resolve, reject) => {
    throw new Error('executor error')
})

// then 抛出异常
const promiseM = new PromiseM((resolve, reject) => {
    resolve(1)
})
promiseM.then(() => {
    throw new Error('executor error')
}).then(() => {}, (error) => {
    console.log(error.message)
})

// reject 链式调用
const promiseM = new PromiseM((resolve, reject) => {
    reject('失败')
})
promiseM.then(value => {
    console.log(value)
}, error => {
    console.log(error)
    return 10000
}).then(value => {
    console.log(value)
})

6. 处理异步情况

console.log(1)
const promiseM = new PromiseM((resolve, reject) => {
    setTimmeout(() => {
        resolve('resolve')
    }, 1000)
})

console.log(2)

promiseM.then(res => {
    console.log(4)
    return 1
}).then(res => {
    console.log(res)
})
console.log(3)
Code 2-1:Promise 异步处理
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class PromiseM {
    status = PENDING;    // promise 状态
    value = undefined;   // 成功之后的值
    error = undefined;   // 失败后的原因
    successCallBack = undefined;
    failCallBack = undefined;
    constructor(fn) {
        return fn(this.resolve, this.reject);
    }
    rosolve = (value) => {
        // 如果状态不是等待 组织程序向下执行
        if (this.status !== PENDING) return
        // 将状态更改为成功
        this.status = FULFILLED;
        // 保存成功后的值
        this.value = value;
        // 判断成功回调是否存在,如果存在则调用
        this.successCallBack && this.successCallBack(this.value)
    };
    reject = (error) => {
        // 如果状态不是等待 组织程序向下执行
        if (this.status !== PENDING) return
        // 将状态更改为失败
        this.status = REJECTED;
        // 保存失败后的原因
        this.error = error;
        // 判断失败回调是否存在,如果存在则调用
        this.failCallBack && this.failCallBack(this.value)
    };
    then = (successCallBack, failCallBack?) => {
        if(this.status === FULFILLED) {
            return successCallBack(this.value);
        }
        if(this.status === REJECTED) {
            return failCallBack(this.error)
        }
        this.successCallBack = successCallBack
        this.failCallBack = failCallBack
    }
}
Code 2-2:一个 Promise 实例多次调用 then 方法
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class PromiseM {
    status = PENDING;    // promise 状态
    value = undefined;   // 成功之后的值
    error = undefined;   // 失败后的原因
    successCallBack = [];
    failCallBack = [];
    constructor(fn) {
        return fn(this.resolve, this.reject);
    }
    resolve = (value) => {
        // 如果状态是不是等待 组织程序向下执行
        if(this.status !== PENDING) return
        // 将状态更改为成功
        this.status = FULFILLED;
        // 保存成功后的值
        this.value = value;
        // 判断成功回调是否存在,如果存在则调用,通过循环依次调用
        while(this.successCallBack.length > 0) {
            this.successCallBack.shift()(this.value)
        }
    };
    reject = (error) => {
        // 如果状态不是等待 组织程序向下执行
        if(this.status !== PENDING) return
        // 将状态更改为失败
        this.status = REJECTED;
        // 保存失败后的原因
        this.error = error;
        // 判断失败回调是否存在,如果存在则调用,通过循环依次调用
        while(this.failCallBack.length > 0) {
            this.failCallBack.shift()(this.value)
        }
    };
    then = (successCallBack, failCallBack?) => {
        if(this.status === FULFILLED) {
            return successCallBack(this.value)
        }
        if(this.status === REJECTED) {
            return failCallBack(this.error)
        }
        this.successCallBack.push(successCallBack)
        this.failCallBack.push(failCallBack)
    }
}
Code 2-3: Promise then 链式调用、then 方法返回值
then = (successCallback, failCallBack?) => {
    console.log('then', this.status);

    return new PromiseM((resolve, reject) => {
        if(this.status === FULFILLED) {
            console.log(this.value, 'success');
            return resolvePromise(successCallBack(this.value), resolve, reject);
        }
        if(this.status === REJECTED) {
            return failCallBack(this.error)
        }
        this.successCallBack.push(successCallBack)
        this.failCallBack(failCallBack)
    })
}

function resolvePromise(x, resolve, reject) {
    if(x instanceod PromiseM) {
        x.then(resolve, reject)
    } else {
         resolve(x)   
    }
}

Code 2-4:校验之避免循环调用
then = (successCallBack, failCallBack?) => {
    const promise2 = new PromiseM((resolve, reject) => {
        if(this.status === FULFILLED) {
            return setTimeout(() => {
                resolvePromise(promise2, successCallBack(this.value), resolve, reject);
            }, 0)
        }
        if(this.status === REJECTED) {
            return failCallBack(this.error)
        }
        this.successCallBack.push(successCallBack)
        this.failCallBack.push(failCallBack)
    })
    return promise2
};
function resolvePromise(promise2, x, resolve, reject) {
    if(promise2 === x) {
        return reject(new TypeError('Chaining cycle detected for promise #<promise>'))
    }
    if(x instanceof PromiseM) {
        x.then(resolve, reject)
    } else {
        resolve(x)
    }
}
Code 2-5:错误处理
constructor(fn) {
    try {
        fn(this.resolve, this.reject);
    } catch (error) {
        this.reject(error)
    }
}

then = (successCallBack, failCallBack?) => {
    const promise2 = new PromiseM((resolve, reject) => {
        if(this.status === FULFILLED) {
            return setTimeout(() => {
                try {
                    resolvePromise(promise2, successCallBack(this.value), resolve, reject);
                } catch (error) {
                    reject(error)
                }
            }, 0)
        }
        if(this.status === REJECTED) {
            return failCallBack(this.error)
        }
        this.successCallBack.push(successCallBack)
        this.failCallBack.push(failCallBack)
    })
    return promise2
}
Code 2-6:处理异步情况 (需要重点理解)
resolve = (value) => {
    // 如果状态不是等待 组织程序向下执行
    if(this.status !== PENDING) return
    // 将状态更改为成功
    this.status = FULFILLED;
    // 保存成功后的值
    this.value = value;
    console.log('IN RESOLVE');

    // 判断成功回调是否存在,如果存在则调用
    while (this.successCallback.length > 0) {
        this.successCallBack.shift()()
    }
};

reject = (error) => {
    // 如果状态不是等待 组织向下执行
    if(this.status !== PENDING) return
    // 将状态更改为失败
    this.status = REJECTED;
    // 判断失败回调是否存在,如果存在则调用
    while (this.failCallBack.length > 0) {
        this.failCallBack.shift()()
    }
};

then = (successCallBack, failCallBack?) => {
    const promise2 = new PromiseM((resolve, reject) => {
        if(this.status === FULFILLED) {
            return setTimeout(() => {
                try {
                    resolvePromise(promise2, successCallBack(this.value), resolve, reject);
                } catch (error) {
                    reject(error)
                }
            }, 0)
        }
        if(this.status === REJECTED) {
            return setTimeout(() => {
                try {
                    resolvePromise(promise2, failCallBack(this.error), resolve, reject);
                } catch (error) {
                    reject(error)
                }
            }, 0)
        }
        this.successCallBack.push(() => {
            setTimeout(() => {
                try {
                    resolvePromise(promise2, successCallBack(this.value), resolve, reject);
                } catch (error) {
                    reject(error)
                }
            }, 0)
        })
        this.failCallBack.push(() => {
            setTimeout(() => {
                try {
                    resolvePromise(promise2, failCallBack(this.error), resolve, reject);
                } catch (error) {
                    reject(error)
                }
            }, 0)
        })
    })
    return promise2
}

三、核心版 Promise

我们还需要处理一些细节,以及 Promise.all 等功能方法。

1. then 方法参数问题

  • then 方法的 resolve/reject 两个参数都是可选参数
  • 没有回调函数的 then 方法 会将 Promise 的状态依次向后传递,直到传递至存在回调函数的 then 方法
  • then 若没有传递参数,则自动补充一个回调函数:获取 resolve 返回值并直接 return,以达到状态传递的效果
// 示例 1
const promiseM = new PromiseM((resolve, reject) => {
    resolve('resolve')
})
promiseM.then().then().then(res => {
    console.log(res)
})
// resolve

// 示例 2
const promiseM = new PromiseM((resolve, reject) => {
    reject('reject')
})
promiseM.then().then().then(res => {
    console.log(res)
}, error => {
    console.log(error)
})

我们需要实现如下面的功能:

promiseM.then().then().then(res => {
    console.log(res)
})
// ↓↓↓↓↓↓↓↓↓ 自动补充如下
promiseM.then(value => value).then(value => value).then(res => {
    console.log(res)
})

2. Promise.all 方法的实现

  • 按照异步代码调用的顺序得到异步代码执行的结果,调用的顺序一定是结果的顺序
  • 数组参数里接收任何类型:Promise 或对象等
  • 返回值是一个 Promise 对象,且可以链式调用 then 方法
  • all 方法中所有的 Promise 对象的状态都是成功时 all 方法最后的状态也是成功的,若存在一个失败,则其状态也会是失败的
  • all 方法是一个静态方法,为解决异步并发问题
const func_1 = () => {
    return new PromiseM((resolve, reject) => {
        setTimeout(() => {
            resolve('func_1')
        }, 2000)
    })
}
const func_2 = () => {
    return new PromiseM((resolve, reject) => {
        resolve('func_2')
    })
}
PromiseM.call(['a','b'func_1(),func_2(),'c']).then(function(result){
    // result -> ['a','b','func_1','func_2','c']
})

3. Promise.resolve 方法的实现

  • 将给定的值转换为 Promise 对象,如果给定值为 Promise 类型,则原封不动传递回去
  • 返回值为一个 Promise 对象,该对象会包裹通过参数传递进去的值
  • resolve 方法是一个静态方法
const func_1 = () => {
    return new PromiseM((resolve, reject) => {
        resolve('func_1')
    })
}
PromiseM.resolve(10).then(value => console.log(value))
PromiseM.resolve(func_1()).then(value => console.log(value))

// 10
// func_1

4. finally 方法的实现

  • 无论当前 Promise 状态是成功还是失败,finally 里的回调函数总会被执行
  • finally 也能够通过链式调用 then 的方式获取当前 Promise 最终返回的结果
  • 不是静态方法
  • finally 的回调函数里也可以 return 一个值,以达到链式调用目的,且调用顺序需注意
const promise_1 = new PromiseM((resolve, reject) => {
    setTimeout(() => {
        resolve('promise_1')
    }, 2000)
})

console.log('-------------');
const promise_2 = new PromiseM((resolve, reject) => {
    reject('失败')
})

promise_2.finally(() => {
    console.log('finally_2')
    return promise_1
}).then(value => {
    console.log(value)
}, error => {
    console.log(error)
})

// finally_2
// 失败

5. catch 方式的实现

  • 用于处理当前 Promise 对象最终状态为失败时的情况
  • 如果不传递失败回调,那么当 Promise 失败时,触发 catch 方法中的回调函数
  • 可在 catch 后链式调用其他方法
const promise = new PromiseM((resolve, reject) => {
    reject('失败')
})

promise.then(value => console.log(value))
    .catch(error => console.log(error))
Code 3-1:then 方法参数问题
then = (successCallBack?, failCallBack?) => {
    successCallBack = successCallBack ? successCallBack : value => value
    failCallBack = failCallBack ? failCallBack : error => { throw error }
    ......
}
Code 3-2:Promise.all 方法的实现
static all(array) {
    let result = []
    let i = 0
    retrun new PromiseM((resolve, reject) => {
        function addData(key, value) {
            result[key] = value
            i++
            if(i === array.length) {
                resolve(result)
            }
        }
        array.forEach((current, index) => {
            if(current instanceof PromiseM) {
                current.then(value => addData(index, value), error => reject(error))
            } else {
                addData(index, current)
            }
        })
    })
}
Code 3-3:Promise.resolve 方法的实现
static resolve(value) {
    if(value instanceof PromiseM) return value;
    return new PromiseM((resolve) => resolve(value));
}
Code 3-4:finally 方法的实现
finally = (callback) => {
    return this.then(value => {
        return PromiseM.resolve(callback()).then(() => value)
    }, error => {
        return PromiseM.resolve(callback()).then(() => { throw error })
    })
}
Code 3-5:catch 方法的实现
catch(failCallBack) {
    return this.then(undefined, failCallBack)
}

四、完整版 Promise

整合代码

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class PromiseM {
    status = PENDING;    // promise 状态
    value = undefined;   // 成功之后的值
    error = undefined;   // 失败后的原因
    successCallBack = [];
    failCallBack = [];
    constructor(fn) {
        try {
            fn(this.resolve, this.reject);
        } catch (error) {
            this.reject(error);
        }
    }
    resolve = (value) => {
        // 如果状态不是等待 组织程序向下执行
        if(this.status !== PENDING) return;
        // 将状态更改为成功
        this.status = FULFILLED;
        // 保存成功后的值
        this.value = value
        // 判断成功回调是否存在,如果存在则调用
        while(this.successCallBack.length > 0) {
            this.successCallBack.shift()();
        }
    }
    reject = (error) => {
         // 如果状态不是等待 组织程序向下执行
        if(this.status !== PENDING) return;
        // 将状态更改为失败
        this.status = REJECTED;
        // 保存失败后的原因
        this.error = error
        // 判断失败回调是否存在,如果存在则调用
        while(this.failCallBack.length > 0) {
            this.failCallBack.shift()();
        }
    }
    then = (successCallBack?, failCallBack?) => {
        successCallBack = successCallBack ? successCallBack : (value) => value;
        failCallBack = failCallBack
            ? failCallBack
            : (error) => {
                throw error;
            }
        const promise2 = new PromiseM((resolve, reject) => {
            if(this.status === FULFILLED) {
                retrun setTimeout(() => {
                    try {
                        resolvePromise(
                            promise2,
                            successCallBack(this.value),
                            resolve,
                            reject
                        );
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            }
            if(this.status === REJECTED) {
                return setTimeout(() => {
                    try {
                        resolvePromise(promise2, failCallBack(this.error), resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            }
            this.successCallBack.push(() => {
                setTimeout(() => {
                    try {
                        resolvePromise(
                            promise2,
                            successCallBack(this.value),
                            resolve,
                            reject
                        )
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            })
            this.failCallBack.push(() => {
                setTimeout(() => {
                    try {
                        resolvePromise(promise2, failCallBack(this.error), resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            })
        })
        return promise2
    }
    finally = (callback) => {
        return this.then(value => {
            return PromiseM.resolve(callback()).then(() => value)
        }, error => {
            return PromiseM.resolve(callback()).then(() => { throw error })
        })
    }
    catch(failCallBack) {
        return this.then(undefined, failCallBack)
    }
    static all(array) {
        let result = [];
        let i = 0;
        return new PromiseM((resolve, reject) => {
            function addData(key, value) {
                result[key] = value;
                i++;
                if(i === array.length) {
                    resolve(result)
                }
            }
            array.forEach((current, index) => {
                if(current instanceof PromiseM) {
                    current.then(
                        (value) => addData(index, value),
                        (error) => reject(error)
                    )
                } else {
                    addData(index, current)
                }
            })
        })
    
    }
    static resolve(value) {
        if(value instanceof PromiseM) return value;
        return new PromiseM((resolve) => resolve(value));
    }
}

function resolvePromise(promise2, x, resolve, reject) {
    if(promise2 === x) {
        return reject(
            new TypeError('Chaining cycle detected for promise #<Promise>')
        )
    }
    if(x instanceof PromiseM) {
        x.then(resolve, reject)
    } else {
        resolve(x)
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值