手写promise原理

整体内容概述

  1. 实现Promise构造函数
  2. 实现Promise.then方法
  3. 实现Promise.catch方法
  4. 实现Promise.resolve
  5. 实现Promise.reject
  6. 实现Promise.all方法
  7. 实现Promise.race方法

1.实现Promise构造函数

在实现promise构造函数前,我们先看一下平时我们是怎样定义一个promise的

const P = new Promise((res, rej) => {
    res('ok')
})

我们可以看出promise接受一个参数,且这个参数为一个方法。据此,我们来定义我们自己的promise构造函数

;(function(window){
// 定义我们自己的promise构造函数
class MyPromise {
    constructor(extore) {
        const resolevd = ()=> {
        }
        const rejected = ()=> {
        }
        extore(resolevd, rejected);
    }
}

// 将我们自己定义的promise构造函数暴露出去
window.MyPromise = MyPromise
})(window)

promise会有三种状态 pending、resolved、rejected,此时我们需要一个变量status来记录promise的状态,并且分别需要一个变量来记录promise的值及错误信息。

;(function(window){
const PENDING = 'pendgin';
const RESOLVED = 'resolved';
const REJECTED = 'rejected';
// 定义我们自己的promise构造函数
class MyPromise {
    // 三个变量分别存储状态、值及错误信息
    status = PENDING;
    data = undefined;
    errMessage = undefined;
    
   
    constructor(extore) {
        const resolevd = (value)=> {
            // 因为resolevd或者rejected只能执行一次,即status状态为pending的时候
           if(this.status !== PENDING) return;
           this.data = value;
           this.status = RESOLVED;
        }
        const rejected = (err)=> {
            if(this.status !== PENDING) return;
            this.errMessage = err;
            this.status = REJECTED;

        }
        extore(resolevd, rejected);
    }
}

// 将我们自己定义的promise构造函数暴露出去
window.MyPromise = MyPromise
})(window)

当我们这样使用promise的时候

const P = new Promise((res, rej) => {
    res(1)
})
P.then(data => {
    console.log(data)
})

当执行到then的时候,会传入两个回调函数resolved和rejected,并且我们在初始化promise的时候已经执行了resolved或者rejected函数,所以status会是resolved或者rejected。所以我们需要在then方法里实现resolved和rejected

;(function(window){
const PENDING = 'pendgin';
const RESOLVED = 'resolved';
const REJECTED = 'rejected';
// 定义我们自己的promise构造函数
class MyPromise {
    // 三个变量分别存储状态、值及错误信息
    status = PENDING;
    data = undefined;
    errMessage = undefined;
    
   
    constructor(extore) {
        const resolevd = (value)=> {
            // 因为resolevd或者rejected只能执行一次,即status状态为pending的时候
           if(this.status !== PENDING) return;
           this.data = value;
           this.status = RESOLVED;
        }
        const rejected = (err)=> {
            if(this.status !== PENDING) return;
            this.errMessage = err;
            this.status = REJECTED;

        }
        extore(resolevd, rejected);
    }
    // 新增代码
    then(onResolved, onRejected){
        if (this.status === RESOLVED) {
            OnResolved(this.data);
        }
        if (this.status === REJECTED) {
            onRejected(this.errMessage);
        }

    }
}

// 将我们自己定义的promise构造函数暴露出去
window.MyPromise = MyPromise
})(window)

但是当我们这样使用promise的时候

const P = new Promise((res, rej) => {
    // 模拟后台请求
    setTimeOut(() => {
        res(1)
    }, 1000)
})
P.then(data => {
    console.log(data)
})

在promise初始化完成后,会立即执行P.then,但是由于promise的初始化的时候内部是异步操作,所以当执行到then的时候,status会是pending状态。此时我们需要使用发布订阅模式将then方法里的回调函数保存起来,等异步函数执行的时候,再去执行then里保存的方法。

;(function(window){
const PENDING = 'pendgin';
const RESOLVED = 'resolved';
const REJECTED = 'rejected';
// 定义我们自己的promise构造函数
class MyPromise {
    // 三个变量分别存储状态、值及错误信息
    status = PENDING;
    data = undefined;
    errMessage = undefined;
    // 新增代码
    callBackList = [];
    
   
    constructor(extore) {
        const resolevd = (value)=> {
            // 因为resolevd或者rejected只能执行一次,即status状态为pending的时候
           if(this.status !== PENDING) return;
           this.data = value;
           this.status = RESOLVED;
            // 新增代码
            this.callBackList.map(({onResolved} = {}) => {
                onResolved(value)
            })
        }
        const rejected = (err)=> {
            if(this.status !== PENDING) return;
            this.errMessage = err;
            this.status = REJECTED;
            // 新增代码
            this.callBackList.map(({onRejected} = {}) => {
                onRejected(err)
            })


        }
        extore(resolevd, rejected);
    }
    then(onResolved, onRejected){
        if (this.status === RESOLVED) {
            setTimeOut(() => {
                OnResolved(this.data);
            })
           
        }
        if (this.status === REJECTED) {
            setTimeOut(() => {
                onRejected(this.errMessage);

            })

        }
        // 新增代码
        if (this.status === PENDING) {
            this.callBackList.push({
                onResolved: () => {
                  onResolved(this.data) 
                },
                onRejected: () => {
                    onRejected(this.errorMessage)
                }

            })
        }

    }
}

// 将我们自己定义的promise构造函数暴露出去
window.MyPromise = MyPromise
})(window)

至此,我们的promise构造函数基本完成了。

2.实现then方法

我们知道promise的then方法可以实现连缀写法,所以我们的then方法返回的肯定也是一个promise对象。基于此,对我们上边的代码进行修改

;(function(window){
const PENDING = 'pendgin';
const RESOLVED = 'resolved';
const REJECTED = 'rejected';
// 定义我们自己的promise构造函数
class MyPromise {
    // 三个变量分别存储状态、值及错误信息
    status = PENDING;
    data = undefined;
    errMessage = undefined;
    callBackList = [];
    
   
    constructor(extore) {
        const resolevd = (value)=> {
            // 因为resolevd或者rejected只能执行一次,即status状态为pending的时候
           if(this.status !== PENDING) return;
           this.data = value;
           this.status = RESOLVED;
            this.callBackList.map(({onResolved} = {}) => {
                onResolved(value)
            })
        }
        const rejected = (err)=> {
            if(this.status !== PENDING) return;
            this.errMessage = err;
            this.status = REJECTED;
            this.callBackList.map(({onRejected} = {}) => {
                onRejected(err)
            })


        }
        extore(resolevd, rejected);
    }
    then(onResolved, onRejected){
        // 改动点:返回一个新的promise
        return new MyPromise((resolve, reject) => {

          if (this.status === RESOLVED) {
            setTimeOut(() => {
                OnResolved(this.data);
            })
           
            }
        if (this.status === REJECTED) {
            setTimeOut(() => {
                onRejected(this.errMessage);

            })

        }
        if (this.status === PENDING) {
            this.callBackList.push({
                onResolved: () => {
                  onResolved(this.data) 
                },
                onRejected: () => {
                    onRejected(this.errorMessage)
                }

            })
        }
       })


    }
}

// 将我们自己定义的promise构造函数暴露出去
window.MyPromise = MyPromise
})(window)

接下来看一下then方法的回调函数里可能出现的情况

const P = new Promise((res, rej) => {
    // 模拟后台请求
    setTimeOut(() => {
        res(1)
    }, 1000)
})
P.then(data => {
    console.log(data) // 第一种情况:无返回值
    // return data // 第二种情况:有返回值,但是返回值不是一个promise对象
    // return new Promise((resoleved, rejected) => { // 第三种情况,有返回值,而且返回值是个一个promise对象
    //   resolved(data)
    // })

})
.then(data => {
    console.log(data)
})

由此我们可以总结为,then方法的回调函数里无返回值或者返回值不是一个promise对象时,我们直接将回调函数里的值resolve或者reject出来即可,但是当返回值为一个promise对象时,我们需要将返回的promise resolve或者reject出来的值传给连缀写法里的then函数的回调函数。所以我们可以判断一下then方法回调函数里返回的不同内容进行不同的处理。

;(function(window){
const PENDING = 'pendgin';
const RESOLVED = 'resolved';
const REJECTED = 'rejected';

// 新增代码:封装一个函数来统一处理我们对then回调函数返回值的处理
const handle = (cb, val, resolve, reject) => {
    const result = cb(val);
    if (result instanceof MyPromise) { // 返回的是一个promise对象
        result.then(
            value => {
                resolve(value)
            },
            reason => {
                reject(reason) 
            }
        )
    } else { // 没有返回值或者返回的不是一个promise对象
        resolve(result)
    }
}
// 定义我们自己的promise构造函数
class MyPromise {
    // 三个变量分别存储状态、值及错误信息
    status = PENDING;
    data = undefined;
    errMessage = undefined;
    callBackList = [];
    
   
    constructor(extore) {
        const resolevd = (value)=> {
            // 因为resolevd或者rejected只能执行一次,即status状态为pending的时候
           if(this.status !== PENDING) return;
           this.data = value;
           this.status = RESOLVED;
            this.callBackList.map(({onResolved} = {}) => {
                onResolved(value)
            })
        }
        const rejected = (err)=> {
            if(this.status !== PENDING) return;
            this.errMessage = err;
            this.status = REJECTED;
            this.callBackList.map(({onRejected} = {}) => {
                onRejected(err)
            })


        }
        extore(resolevd, rejected);
    }
    then(onResolved, onRejected){
        // 新增代码:为onResolved和OnRejected两个参数设置默认值
        onResolved === ‘function’? onResolved: val => val; // 当onResolved为一个方法时,onResolved即为次方法。当不是的时候,自己写一个函数,这个函数的执行结果将返回上一个promise的值。
        onRejected === 'function'? onRejected: (err) => {
            throw err; // 当onRejected不是一个方法的时候,抛出错误
        }
        return new MyPromise((resolve, reject) => {

          if (this.status === RESOLVED) {
            setTimeOut(() => {
               // 改动点
                handle(OnResolved, this.data, resolve, reject);
            })
           
            }
        if (this.status === REJECTED) {
            setTimeOut(() => {
                // 改动点
                handle(onRejected, this.errMessage, resolve, reject);

            })

        }
        if (this.status === PENDING) {
            this.callBackList.push({
                onResolved: () => {
                  // 改动点
                   handle(onResolved, this.data, resolve, reject);
                },
                onRejected: () => {
                    // 改动点
                    handle(onRejected, this.errMessage, resolve, reject)
                }

            })
        }
       })


    }
}

// 将我们自己定义的promise构造函数暴露出去
window.MyPromise = MyPromise
})(window)

然后再让我们把捕获异常加上

;(function(window){
const PENDING = 'pendgin';
const RESOLVED = 'resolved';
const REJECTED = 'rejected';

// 封装一个函数来统一处理我们对then回调函数返回值的处理
const handle = (cb, val, resolve, reject) => {
    // 改动点:增加异常捕获
   try{
    const result = cb(val);
    if (result instanceof MyPromise) { // 返回的是一个promise对象
        result.then(
            value => {
                resolve(value)
            },
            reason => {
                reject(reason) 
            }
        )
    } else { // 没有返回值或者返回的不是一个promise对象
        resolve(result)
    }
   }catch(e){
    reject(e)
   }
}
// 定义我们自己的promise构造函数
class MyPromise {
    // 三个变量分别存储状态、值及错误信息
    status = PENDING;
    data = undefined;
    errMessage = undefined;
    callBackList = [];
    
   
    constructor(extore) {
        const resolevd = (value)=> {
            // 因为resolevd或者rejected只能执行一次,即status状态为pending的时候
           if(this.status !== PENDING) return;
           this.data = value;
           this.status = RESOLVED;
            this.callBackList.map(({onResolved} = {}) => {
                onResolved(value)
            })
        }
        const rejected = (err)=> {
            if(this.status !== PENDING) return;
            this.errMessage = err;
            this.status = REJECTED;
            this.callBackList.map(({onRejected} = {}) => {
                onRejected(err)
            })


        }
        // 改动点:添加异常捕获
        try{
            extore(resolevd, rejected);
        }catch(e) {
            rejected(e)
        }
       
    }
    then(onResolved, onRejected){
        // 为onResolved和OnRejected两个参数设置默认值
        onResolved === ‘function’? onResolved: val => val; // 当onResolved为一个方法时,onResolved即为次方法。当不是的时候,自己写一个函数,这个函数的执行结果将返回上一个promise的值。
        onRejected === 'function'? onRejected: (err) => {
            throw err; // 当onRejected不是一个方法的时候,抛出错误
        }
        return new MyPromise((resolve, reject) => {

          if (this.status === RESOLVED) {
            setTimeOut(() => {
                handle(OnResolved, this.data, resolve, reject);
            })
           
            }
        if (this.status === REJECTED) {
            setTimeOut(() => {
                handle(onRejected, this.errMessage, resolve, reject);

            })

        }
        if (this.status === PENDING) {
            this.callBackList.push({
                onResolved: () => {
                   handle(onResolved, this.data, resolve, reject);
                },
                onRejected: () => {
                    handle(onRejected, this.errMessage, resolve, reject)
                }

            })
        }
       })


    }
}

// 将我们自己定义的promise构造函数暴露出去
window.MyPromise = MyPromise
})(window)

至此,我们的then方法可以说是实现了。

3.实现catch方法

catch方法的作用其实与then方法里的第二个回调函数一样,因此我们可以在then方法的基础上实现catch方法。

catch (onRejected) {
    return this.then(undefined, onRejected)
}

是的,你没有看错,就是这么简单!

4.实现Promise.resolve

我们都知道,Promise.resolve方法接受的参数可以分为以下三种情况

  1. 不是promise
  2. 成功状态的promise
  3. 失败状态的promise

通过上边我们对then方法的封装,Promise.resolve可以这样实现

resolve(val) {
    // 返回一个promise对象,原因同then方法
    return new MyPromise((resolve, reject) => {
        if(val instanceof new Mypromise){  // val 是promise
            val.then(
                value => {resolve(value)},
                 reason => {reject(reason)}
            )
        }else { // val 不是promise
            resolve(val)
        }
    })
}

5.Promise.reject

Promsie.reject相对Promise.resolve比较简单,因为它只需要考虑reject的情况就可以了。

reject(reason){
    return new MyPromise((resolve, reject) => {
        reject(reason);
    })
}

6.Promise.all

首先,这个方法也会返回一个promise,而且这个promise的状态由所有promise产生的结果决定。

分为两种情况,第一种情况是,如果有一个promise的状态为reject,则最终的状态为reject;第二种情况是,所有的promise的状态为resolve,则最终状态为resolve,并且需要将每个promise产生的值返回出去。

all(promiseList = []) {
    const promiseLenth = promiseList.length;
    const values = new Array(promiseLenth);
    let resolvedCount = 0;
    return new MyPromise((resolve, reject) => {
        promiseList.forEach((p, index) => {
            p.then(
                value => {
                    values[index] = value; // 将单个promise状态为resolve的值保存起来
                    resolvedCount++;
                    if(resolvedCount === promiseLenth) { // 当所有promise状态都为resolved时,将存储每个promise值的数组返回。
                        resolve(values)
                    }
                },
                reason => { // 只要有一个失败,则状态为reject
                    reject(reason)
                }
            )
        })
    })
}

这样看着貌似可以了,但是还有个问题就是,我们的promise.all接受的参数(数组)里并不一定都是promise。例如 promise.all([1, 2, 3])。所以我们还需要做的一个工作是将不是promise的元素包装成一个promise(我们可以直接使用前边封装的promise.resolve()方法)。

all(promiseList = []) {
    const promiseLenth = promiseList.length;
    const values = new Array(promiseLenth);
    let resolvedCount = 0;
    return new MyPromise((resolve, reject) => {
        promiseList.forEach((p, index) => {
            MyPromise.resolve(p).then( // 可以直接使用我们前边封装的MyPromise.resolve将每个p包装成一个promise。
                value => {
                    values[index] = value; // 将单个promise状态为resolve的值保存起来
                    resolvedCount++;
                    if(resolvedCount === promiseLenth) { // 当所有promise状态都为resolved时,将存储每个promise值的数组返回。
                        resolve(values)
                    }
                },
                reason => { // 只要有一个失败,则状态为reject
                    reject(reason)
                }
            )
        })
    })
}

7. Promise.race

race方法是只要有一个promise的状态为resolve或者reject,则状态为resolve或者reject。

race(promiseList = []){
    return new MyPromise((resolve, reject) => {
        promiseList.forEach((p, index) => {
            MyPromise.resolve(p).then(
                value => {resole(value)}, // 只要有一个成功,则返回的状态为resolve
                reason => {reject(reason)} // 只要有一个失败,则返回的状态为reject
            )
        })
    })
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值