Promise的实现

266 阅读7分钟

Promise是什么?

  1. Promise是一个立即执行函数,一旦new ,函数会立即执行
  2. 立即执行函数有2个参数,成功后调动resolve、失败后调用reject,
  3. Promise有3个状态,pending、fulfilled、rejected
  4. Promise上有一个then方法
  5. 上一个成功后的状态resolve的值会传递给下一个then的成功后的结果,上一个失败后的状态后的结果会传递给下一个reject
  6. Promise的状态一经改变就无法修改,resolve 或 reject后就无法改变
  7. Promise链式调用每次都返回一个新的Promise
  8. 如果Promise返回的是普通值(非Promise非抛错)的情况,会发生值穿透

Promise立即执行

class Promise {
    construcotr(executor){
        executor();
    }    
}
module.exprots = Promise;

Promise3种状态

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const ONREJECTED = 'onrejected';
class Promise {
    constructor(executor){
        this.status = PENDING;
         executor();   
    }    
}

Promise2个参数

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const ONREJECTED = 'onrejected';
class Promise {
    constructor(executor){
        this.status = PENDING; // 默认pending态
        this.value = null; //  成功后的结果
        this.reason = null; // 失败后的结果
        const resolve = (value) => {
            this.value = value;
        }
        const reject = (reason) => {
            this.reason = reason;
        }
        executor(resolve,reject);
    }    
}

Promise的状态无法修改

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const ONREJECTED = 'onrejected';
class Promise {
    constructor(executor){
        this.status = PENDING; // 默认pending态
        this.value = null; //  成功后的结果
        this.reason = null; // 失败后的结果
        const resolve = (value) => {
            // 只有在pending态的时候才可以将状转变为resolve
            if(this.status === PENDING) {
                this.value = value;
                this.status = FULFILLED;
            }
            
        }
        const reject = (reason) => {
            if(this.status === ONREJECTED){
                this.reason = reason;
                this.status = ONREJECTED;
            }            
        }
        executor(resolve,reject);
    }
}

Promise的then方法

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const ONREJECTED = 'onrejected';
class Promise {
    constructor(executor){
        this.status = PENDING; // 默认pending态
        this.value = null; //  成功后的结果
        this.reason = null; // 失败后的结果
        this.successCb = []; // 成功后的事件队列
        this.failCb = [];  // 失败后的事件队列
        const resolve = (value) => {
            // 只有在pending态的时候才可以将状转变为resolve
            if(this.status === PENDING) {
                this.value = value;
                this.status = FULFILLED;
            }
            
        }
        const reject = (reason) => {
            if(this.status === ONREJECTED){
                this.reason = reason;
                this.status = ONREJECTED;
            }            
        }
        executor(resolve,reject);
    },
    // then 有2个参数,一个是成功后的回调函数onfulfiled, 一个是失败后的回调函数onrejected
    then(onfulfiled,onrejected) {
        // 如果此时Promise的状态是成功态,则可以执行成功后的回调
        if(this.status === FULFILLED){
            onfulfiled();
        }
        if(this.status === ONREJECTED) {
            onrejected();
        }
        if(this.status === PENDING) {
        }
    }
}

解决Promise的then方法中的异步问题

通过发布订阅模式,在then中将需要执行的事件放入事件队列,在resolve或reject的时候再一起调用

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const ONREJECTED = 'onrejected';
class Promise {
    constructor(executor){
        this.status = PENDING; // 默认pending态
        this.value = null; //  成功后的结果
        this.reason = null; // 失败后的结果
        this.successCb = []; // 成功后的事件队列
        this.failCb = [];  // 失败后的事件队列
        const resolve = (value) => {
            // 只有在pending态的时候才可以将状转变为resolve
            if(this.status === PENDING) {
                this.value = value;
                this.status = FULFILLED;
                this.successCb.forEach((fn) =>fn()); // resolve时发布之前订阅的异步事件
            }
            
        }
        const reject = (reason) => {
            if(this.status === ONREJECTED){
                this.reason = reason;
                this.status = ONREJECTED;
                this.failCb.forEach(fn => fn());
            }            
        }
        executor(resolve,reject);
    },
    // then 有2个参数,一个是成功后的回调函数onfulfiled, 一个是失败后的回调函数onrejected
    then(onfulfiled,onrejected) {
        // 如果此时Promise的状态是成功态,则可以执行成功后的回调
        if(this.status === FULFILLED){
            this.successCb.push(() =>{
                onfulfiled();
            })
        }
        if(this.status === ONREJECTED) {
            this.failCb.push(() =>{
                 onrejected();
            }) 
        }
        if(this.status === PENDING) {
        // 如果Promise此时执行的是一个异步事件,则PromisePENDING态说明,需要等待异步时机到达后才能执行
            this.successCb.push(() =>{
                onfulfiled();
            })
            this.failCb.push(() =>{
                onrejected();
            })
        }
    }
}

Promise的链式调用

链式调用与Jquery中返回this不同的是,Promise是通过返回一个新的Ppromsie实例来实现链式调用

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const ONREJECTED = 'onrejected';
class Promise {
    constructor(executor){
        this.status = PENDING; // 默认pending态
        this.value = null; //  成功后的结果
        this.reason = null; // 失败后的结果
        this.successCb = []; // 成功后的事件队列
        this.failCb = [];  // 失败后的事件队列
        const resolve = (value) => {
            // 只有在pending态的时候才可以将状转变为resolve
            if(this.status === PENDING) {
                this.value = value;
                this.status = FULFILLED;
                this.successCb.forEach((fn) =>fn()); // resolve时发布之前订阅的异步事件
            }
            
        }
        const reject = (reason) => {
            if(this.status === ONREJECTED){
                this.reason = reason;
                this.status = ONREJECTED;
                this.failCb.forEach(fn => fn());
            }            
        }
        executor(resolve,reject);
    },
    // then 有2个参数,一个是成功后的回调函数onfulfiled, 一个是失败后的回调函数onrejected
    then(onfulfiled,onrejected) {
        const promise2 = new Promise((resolve,reject) => {
            // 如果此时Promise的状态是成功态,则可以执行成功后的回调
            if(this.status === FULFILLED){
                this.successCb.push(() => {                    
                    // resvole(x) 将上一次成功后的返回的值传递一个下一个Promsie的resolve
                    // 如果写成这样在resolvePromise中是获取不到Promise2的,所以需要将下一个Promsise
                    // 的过程通过异步函数包裹起来
                    setTimeout(() => {
                        try {
                            let x = onfulfiled(this.value);
                            resolvePromsie(x,promise2,resolve,reject);
                        } catch(err) {
                            reject(err);
                        }
                    },0)
                })
            }
            if(this.status === ONREJECTED) {
                this.failCb.push(() => {
                     setTimeout(() =>{
                         try {
                             let x = onrejected(this.reason);
                             resolvePromsie(x,promise2,resolve,reject);
                         } catch(err) {
                             reject(err);
                         }
                     },0)
                }) 
            }
            if(this.status === PENDING) {
                this.successCb.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onfulfiled(this.value);
                            resolvePromsie(x,promise2,resolve,reject);
                        } catch(err) {
                            reject(err);
                        }
                    },0)
                })
                this.failCb.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onrejected(this.reason);
                            resolvePromsie(x,promise2,resolve,reject);
                        } catch (err) {
                            reject(err);
                        }
                    },0)
                })
            }
        });
        return promise2;
    }
}
function resolvePromsie(x,promsie2,resolve,reject){
    // 如果上一次的返回值x 与 promise2 是同一个引用,即存在自己等自己执行的情况
    if(x == promise2){
        return reject(new Error('type error'));
    }
    if((typeof x !== null && typeof x == 'object') || typeof x === 'function'){
       try{
            let then = x.then;
            // 如果上一次返回的是Promsie, 则继续递归处理,用当前x调用then方法,
            if(typeof then === 'function'){
                then.call(x,(y) => {
                    resolvePromsie(y, promsie2,resovle,reject);
                },(r) => {
                    reject(r)
                })
            } else {
            // 如果是普通值,则直接resolve掉
                resolve(x);
            }
       } catch(err) {
           reject(err)
       }
    } else {
        resolve(x);
    }
}

Promise中resolve或reject的仍然还是Promsie

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const ONREJECTED = 'onrejected';
class Promise {
    constructor(executor){
        this.status = PENDING; // 默认pending态
        this.value = null; //  成功后的结果
        this.reason = null; // 失败后的结果
        const resolve = (value) => {
            // 如果此时的value仍然是Pormise,则仍需调用value的then方法
            if(value instanceof Promsie){
                value.then(resolve,reject);
            }
            if(this.status === PENDING) {
                this.value = value;
                this.status = FULFILLED;
            }            
        }
        const reject = (reason) => {
            // 如果此时reason的类型仍然是Pormise,则仍需调用reason的then方法
            if(reason instanceof Promise){
                reason.then(resolve,reject);
            }
            if(this.status === ONREJECTED){
                this.reason = reason;
                this.status = ONREJECTED;
            }            
        }
        executor(resolve,reject);
    }
}

完整版实现

Promise中resolve或reject的是普通值

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const ONREJECTED = 'onrejected';
class Promise {
    constructor(executor){
        this.status = PENDING; // 默认pending态
        this.value = null; //  成功后的结果
        this.reason = null; // 失败后的结果
        this.successCb = []; // 成功后的事件队列
        this.failCb = [];  // 失败后的事件队列
        const resolve = (value) => {
            // 只有在pending态的时候才可以将状转变为resolve
            if(this.status === PENDING) {
                this.value = value;
                this.status = FULFILLED;
                this.successCb.forEach((fn) =>fn()); // resolve时发布之前订阅的异步事件
            }
            
        }
        const reject = (reason) => {
            if(this.status === ONREJECTED){
                this.reason = reason;
                this.status = ONREJECTED;
                this.failCb.forEach(fn => fn());
            }            
        }
        executor(resolve,reject);
    },
    // then 有2个参数,一个是成功后的回调函数onfulfiled, 一个是失败后的回调函数onrejected
    then(onfulfiled,onrejected) {
        // 如果上一次的返回值x是一个普通值,会发生值得穿透
        onfulfiled = typeof x == 'object' ? onfulfiled : v=>v;
        onrejected = typeof x == 'object' > onrejected : reject(){throw new Error()};
        const promise2 = new Promise((resolve,reject) => {
            // 如果此时Promise的状态是成功态,则可以执行成功后的回调
            if(this.status === FULFILLED){
                this.successCb.push(() => {                    
                    // resvole(x) 将上一次成功后的返回的值传递一个下一个Promsie的resolve
                    // 如果写成这样在resolvePromise中是获取不到Promise2的,所以需要将下一个Promsise
                    // 的过程通过异步函数包裹起来
                    setTimeout(() => {
                        try {
                            let x = onfulfiled(this.value);
                            resolvePromsie(x,promise2,resolve,reject);
                        } catch(err) {
                            reject(err);
                        }
                    },0)
                })
            }
            if(this.status === ONREJECTED) {
                this.failCb.push(() => {
                     setTimeout(() =>{
                         try {
                             let x = onrejected(this.reason);
                             resolvePromsie(x,promise2,resolve,reject);
                         } catch(err) {
                             reject(err);
                         }
                     },0)
                }) 
            }
            if(this.status === PENDING) {
                this.successCb.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onfulfiled(this.value);
                            resolvePromsie(x,promise2,resolve,reject);
                        } catch(err) {
                            reject(err);
                        }
                    },0)
                })
                this.failCb.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onrejected(this.reason);
                            resolvePromsie(x,promise2,resolve,reject);
                        } catch (err) {
                            reject(err);
                        }
                    },0)
                })
            }
        });
        return promise2;
    }
}
function resolvePromsie(x,promsie2,resolve,reject){
    // 如果上一次的返回值x 与 promise2 是同一个引用,即存在自己等自己执行的情况
    if(x == promise2){
        return reject(new Error('type error'));
    }
    if((typeof x !== null && typeof x == 'object') || typeof x === 'function'){
       try{
            let then = x.then;
            // 如果上一次返回的是Promsie, 则继续递归处理,用当前x调用then方法,
            if(typeof then === 'function'){
                then.call(x,(y) => {
                    // 此时将上一次成功后的返回值y,传递给下一个处理函数
                    resolvePromsie(y, promsie2,resovle,reject);
                },(r) => {
                    reject(r)
                })
            } else {
            // 如果是普通值,则直接resolve掉
                resolve(x);
            }
       } catch(err) {
           reject(err)
       }
    } else {
        resolve(x);
    }
}

Promise的链式调用应用

1.如果当前promsie返回的不是promise,则会将成功或者失败后的值,传递给外层的then,(失败返回undefned)也会进入外层then的成功

function read(...args) {
    return new Promise((resolve,reject) => {
         fs.readFile(...args,(err,data) => {
             if(err) console.log(err)
             resolve(data)
	  })
    })
}
read('./name.txt','utf8').then(data => {
    return 100;
},err =>{
    console.log(err)
})
.then((data) => {
    console.log(data)
})
  • 如果读取成功,传入外层的then的data里面
  • 如果读取失败,则console.log(err)返回的是undefined,还是会将undefined传入到data中

2.如果当前promise执行出错了,抛出异常,则会走当前的失败,如果当前没有失败,则会走外层的失败,外层没有失败,则会走catch

read("./name1.txt").then((res) => {
    throw new Error('err')
},(err) => {
    console.log("err1",err)
}).then(res => {
    console.log(res)
},(err) => {
    console.log("err2",err)
}).catch(err => {
    	console.log('catch',err)
})
  1. 如果当前返回的是Promise,则会将当前的promise的执行后的结果作为下一次then的then的成功或失败
read("./name.txt","utf8").then((res ) => {
    return read("./age.txt",'utf8')
},err => {
    console.log("err1",err)
}).then(data => {
    console.log('s',data)
},(err) => {
    console.log('err2',err)
})

什么时候当前的then走完了,会走下一次then的失败?

  1. then中抛出异常
  1. 返回的promise执行出错了(栗子3中的,读取age文件出错了),会被外层的err2捕捉到

catch 可以理解为then的别名,没有成功只有失败,then(null,err => console.log(err))