Promise原理讲解(二)

181 阅读5分钟

Promise的实现原理

主要难点的实现是链式调用

栗子

let = requestData = ()=>{
    return new Promise((resolve,reject)=>{
        resolve("1");
    });
};

requestData.then((data)=>{
    console.log(data);
},(error)=>{
    console.log(error);
});

Promise状态机

我们现在按照这个栗子来简单的实现下:

const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
class Promise01 {
    constructor(excutor) {
        if (typeof excutor !== "function") {
            throw new Error("promise need a function");
        }
        // 默认状态是等待态
        this.status = PENDING;
        //存放成功的值
        this.resolvedValue = null;
        //存放失败的值
        this.rejectedValue = null;
        // 存放成功的回调
        this.onResolvedCallbacks = [];
        // 存放失败的回调
        this.onRejectedCallbacks = [];
        let self = this;
        let resolve = function(data) {
            if (self.status === PENDING) {
                self.resolvedValue = data;
                self.status = RESOLVED;
                self.onResolvedCallbacks.forEach(fn => fn(self.resolvedValue));
            }
        };
        let reject = function(error) {
            if (self.status === PENDING) {
                self.rejectedValue = error;
                self.status = REJECTED;
                self.onRejectedCallbacks.forEach(fn => fn(self.rejectedValue));
            }
        };
        try {// 执行时可能会发生异常
            excutor(resolve, reject);
        } catch (error) {// promise失败了
            reject(error);
        }
    }
    then(resolvedHandler, rejectedHandler) {
        if (this.status === PENDING) { // 当前既没有完成 也没有失败 
           this.onResolvedCallbacks.push(resolvedHandler);
            this.onRejectedCallbacks.push(rejectedHandler);
        } else if (this.status === RESOLVED) {// 当前成功状态
            resolvedHandler(this.resolvedValue);
        } else if (this.status === REJECTED) {// 当前失败状态
            resolvedHandler(this.rejectedValue);
        }
        //return this;
    }
}

这里虽然实现了.then方法,但是如果需要promise.then().then()的话就会有问题。

Promise的链式调用

this链式调用弊端

我们知道Jquery的链式调用就是返回this,就可以实现链式调用。那Promise里面的链式调用怎么实现的。

我们只需要把上面then方法中的最后一行return this的注释去掉就好了.这里就不重复粘贴代码了。

return this;

let requestData = () => {    
    return new Promise01((resolve, reject) => {
        setTimeout(() => {
            resolve("1");
        }, 1000);
    });
};
requestData().then((data) => {
    console.log(data);
    return "2";}).then((data) => {
    console.log(data);
});

我们run一下这个栗子就知道,返回值是两个“1”。很明显,我的期望值是"1"和“2”.

如果then通过return this来实现链式调用的话,因为是同一个实例,只能返回同样的结果。很显然这并不能满足我们的需求。

每个then注册的回调都返回了不同的结果作为下一个then回调的参数。因此在promie里面真正的链式调用是通过返回一个新的promise实现的。

promise真正的链式调用

真正的promise链式调用是指在当前promise达到fulfilled状态后,即开始下一个promise。即当前promise的then方法里面的返回值需要作为下一个promise的then回调方法的参数值。

首先我们这样修改then方法

then(resolveHandler,rejectedHandler){
    let promise2;
    //同理status为REJECTED和PENDING时也是返回一个promise2
    if(this.status === RESOLVED){
        promise2 = new Promise01((resolve,reject)=>{
            //这便是then成功回调的返回值。我们需要把这个返回值最为下一个then成功回调的参数
            let x = resolveHandler(this.resolvedValue);
            //resolvePromise就是用来解析x和promise2之间的关系
            resolvePromise(promise2,x,resolve,reject);
        });
        return promise2;
    }
    //同理status为REJECTED和PENDING时也是返回一个promose。在后面完整代码中可看

}

那么关键部分就是resolvePromise怎么去处理当前promise的结果和后邻promise的关系。

首先我们考虑当前promise的then成功回调返回的是一个普通值,然后再举一反三。

resolvePromise(promise2,x,resolve,reject){
    if(x!==null && (typeof x === "object" || typeof x === "function")){
        //TODO
    } else {
        //改变promise2的resolvedValue值为上一个then的值
        resolve(x);
    }
}

现在我们来看看特殊类型的返回值怎么处理?

function resolvePromise(promise2, x, resolve, reject) {    
    if (x !== null && (typeof x === "object" || typeof x === "function")) {        
        try {            
            let then = x.then;            
            let called; // 防止成功后调用失败            
            if (typeof then === "function") {
                // 如果then是函数我就认为x是promise                
                then.call(x, y => { // 如果y是promise就继续递归解析promise                    
                    if (called) return;                    
                    called = true;                    
                    resolvePromise(promise2, y, resolve, reject);                
                }, r => { // 只要失败了就失败了                    
                    if (called) return;                    
                    called = true;                    
                    reject(r);                
                });            
            } else {                
                // then是一个普通对象,就直接成功调用成功即可                
                resolve(x);            
            }        
        } catch (error) {            
        if (called) return;            
            called = true;            
            reject(e);        
        }    
    } else {        
        //改变promise2的resolvedValue值为上一个then的值        
        resolve(x);    
    }
}

完整代码

const PENDING = "pending";
const RESOLVED = "fulfilled";
const REJECTED = "rejected";
function resolvePromise(promise2, x, resolve, reject) {    
    if (x !== null && (typeof x === "object" || typeof x === "function")) {        
        try {            
            let then = x.then;            
            let called; // 防止成功后调用失败            
            if (typeof then === "function") {// 如果then是函数我就认为x是promise   
                 then.call(x, y => { // 如果y是promise就继续递归解析promise 
                   if (called) return;                    
                        called = true;
                        resolvePromise(promise2, y, resolve, reject);
                }, r => { // 只要失败了就失败了
                    if (called) return;
                    called = true;
                    reject(r);
                });
            } else {
                // then是一个普通对象,就直接成功调用成功即可
                resolve(x);
            }
        } catch (error) {
            if (called) return;
            called = true;
            reject(e);
        }
    } else {
        //改变promise2的resolvedValue值为上一个then的值
        resolve(x);
    }}
class Promise01 {
    constructor(excutor) {
        if (typeof excutor !== "function") {
            throw new Error("promise need a function");
        }
        // 默认状态是等待态
        this.status = PENDING;
        //存放成功的值
        this.resolvedValue = null;
        //存放失败的值
        this.rejectedValue = null;
        // 存放成功的回调
        this.onResolvedCallbacks = [];
        // 存放失败的回调
        this.onRejectedCallbacks = [];
        let self = this;
        let resolve = function(data) {
            if (self.status === PENDING) {
                self.resolvedValue = data;
                self.status = RESOLVED;
                self.onResolvedCallbacks.forEach(fn => fn(self.resolvedValue));
            }
        };
        let reject = function(error) {
            if (self.status === PENDING) {
                self.rejectedValue = error;
                self.status = REJECTED;
                self.onRejectedCallbacks.forEach(fn => fn(self.rejectedValue));
            }
        };
        try {// 执行时可能会发生异常
            excutor(resolve, reject);
        } catch (error) {// promise失败了
            reject(error);
        }
    }
    then(resolvedHandler, rejectedHandler) {
        let promise2;
        if (this.status === PENDING) { // 当前既没有完成 也没有失败
            promise2 = new Promise((resolve, reject) => {
                this.onResolvedCallbacks.push(() => {
                    let x = resolvedHandler(this.resolvedValue);
                    // resolvePromise可以解析x和promise2之间的关系
                    resolvePromise(promise2, x, resolve, reject);
                }); 
               this.onRejectedCallbacks.push(() => {
                    //失败的返回值,作为下一个then的失败回调的参数
                    let x = resolvedHandler(this.rejectedValue);
                    // resolvePromise可以解析x和promise2之间的关系
                    resolvePromise(promise2, x, resolve, reject);
                });
            });
        } else if (this.status === RESOLVED) {// 当前成功状态
            promise2 = new Promise((resolve, reject) => {
                //成功的返回值,作为下一个then的成功回调的参数
                let x = resolvedHandler(this.resolvedValue);
                // resolvePromise可以解析x和promise2之间的关系
                resolvePromise(promise2, x, resolve, reject);
            });
        } else if (this.status === REJECTED) {// 当前失败状态
            promise2 = new Promise((resolve, reject) => {
                //失败的返回值,作为下一个then的失败回调的参数
                let x = resolvedHandler(this.rejectedValue);
                // resolvePromise可以解析x和promise2之间的关系
                resolvePromise(promise2, x, resolve, reject);
            });
        }
        return promise2;
    }}

let requestData1 = () => {    
    return new Promise01((resolve, reject) => {
        setTimeout(() => {
            resolve("1");
        }, 1000);
    });};
requestData1().then((data) => {
    console.log(data);
    return "2";}).then((data) => {
    console.log(data);
});

输出“1”和 "2"符合了预期结果。

Promise API 其他API实现

Promise.prototype.catch

Promise01.prototype.catch = (onRejected) => {    
    return Promise01.then(null, onRejected);
};

Promise.prototype.finally

Promise01.prototyoe.finally = (cb) => {
    return Promise01.then(cb,cb);
}

Promise.race

Promise01.race = (...args)=>{
    return new Promose01((resolve,reject)=>{
        for(let i=0,l=args.length;i<l;i++){
            let promise = args[i];
            promise.then(resolve,reject);
        }
    });
}

Promise.all

Promose01.all = (...args)=>{
    return new Promose01((resolve,reject)=>{
        let index = 0;
        let res=[];
        const processData = (i,data)=>{
            res[index] = data;
            index++;
            if(index === args.length){
                resolve(res);
            }
        };
        for(let i =0,l=args.length;i<l;i++){
            let promise = args[i];
            promise.then((data)=>{
                processData(i,data);
            },reject);
        }
    });
};

Promsie.resolve

Promise01.resolve = (val)=>{
    return new Promise01((resolve,reject)=>resolve(val));
}

Promise.reject

Promise01.reject = function(val) {
    return new Promise01((resolve, reject) => reject(val))
;}

Promise.deferred

Promise01.deferred = ()=>{
    let dfd = {};
    dfd = new Promise01((resolve,reject)=>{
        dfd.resolve = resolve;
        dfd.reject = reject;
    });
    return dfd;
};