Promise的源码实现(符合Promise/A+规范)

我们手写一个Promise/A+规范,然后安装测试脚本,以求通过这个规范。

//Promise/A+源代码
// new Promise时,需要传递一个executor执行器,执行器立即执行
// executor接受两个参数,分别是resolve和reject
// promise只能从pending到rejected,或者从pending到fulfilled
// promise的状态一旦确认,就不会再改变
// promise有then方法,then接受两个参数,分别是promise成功的回调onFulfilled
// 和promise失败的回调 onRejected
// 如果调用then时,promise已经成功,则执行onFulfilled,并将promise值作为参数传递进去
// 如果promise已经失败,那么执行onRejected并把promise失败的原因作为参数传递进去
// 如果promise状态是pending,需要将onFulfilled和onRejected函数存放起来,等待状态确定后,再一次将对应的函数执行(发布)
// then的参数onFulfilled和onRejected可以缺省
// promise可以then多次,promise的then方法返回一个promise
// 如果then返回的是一个结果,那么就把这个结果作为参数,传递给下一个then的成功的回调onFulfilled
// 如果then中抛出了异常,那么就会把这个异常作为参数,传递给下一个失败的回调 onRejected
// 如果then返回的是一个promise,那么需要等这个promise,那么会等这个promise执行完,promise如果成功
// 就走下一个then的成功,如果失败,就走下一个then的失败
//pending状态,可以认为是一种中间状态
const PENDING = 'pending';
// fullfilled完成状态,可以认为是成功回调了的状态
const FULFILLED = 'fullfilled';
// reject即为拒绝状态,即失败的状态
const REJECTED = 'reject';
// executor是一个执行器
function Promise(executor){
    let self = this;
    self.status = PENDING;
    self.onFulfilled = [];//成功的回调
    self.onRejected = [];//失败的回调
    // PromiseA+ 2.1
    function resolve(value){
        if(self.status === PENDING){
            self.status = FULFILLED;
            self.value = value;
            self.onFulfilled.forEach(fn=>fn());//PromiseA+ 2.2.6.1
        }
    }
    function reject(reason){
        if(self.status===PENDING){
            self.status = REJECTED;
            self.reason = reason;
            self.onRejected.forEach(fn=>fn());//PromiseA+ 2.2.6.2
        }
    }
    try{
        executor(resolve,reject)
    }catch(e){
        reject(e)
    }
}
// then必须返回一个promise
Promise.prototype.then = function(onFulfilled,onRejected){
    // PromiseA+ 2.2.1/PromiseA+ 2.2.5/PromiseA+ 2.2.7.3/PromiseA+2.2.7.4
    onFulfilled = typeof onFulfilled ==='function'?onFulfilled:value =>value;
    onRejected = typeof onRejected === 'function'?onRejected:reason=>{throw reason};
    let self = this;
    //PromiseA+ 2.2.7
    let Promise2 = new Promise((resolve,reject)=>{
        if(self.status===FULFILLED){
            //PromiseA+2.2.2
            // Promise A+2.2.4----setTimeout
            setTimeout(()=>{
                try{
                    let x = onFulfilled(self.value);
                    resolvePromise(promise2,x,resolve,reject);
                }catch(e){
                    //PromiseA+2.2.7.2
                    reject(e)
                }
            });
        }else if(self.status === REJECTED){
            // PromiseA+ 2.2.3
            setTimeout(()=>{
                try{
                    let x = onRejected(self.reason);
                    resolvePromise(promise2,x,resolve,reject);
                }catch(e){
                    reject(e);
                }
            })
        }else if(self.status===PENDING){
            self.onFulfilled.push(()=>{
                setTimeout(()=>{
                    try{
                        let x = onFulfilled(self.value);
                        resolvePromise(promise2,x,resolve,reject);
                    }catch(e){
                        reject(e);
                    }
                });
            });
        }
    });
    return promise2;
}
function resolvePromise(promise2,x,resolve,reject){
    let self = this;
    //PromiseA+ 2.3.1
    if(promise2===x){
        reject(new TypeError('changing cycle'));
    }
    if(x && typeof x ==="object"|| typeof x ==='function'){
        let used;//PromiseA+ 2.3.3.3.3//只能调用一次
        try{
            let then = x.then;
            if(typeof then === 'function'){
                //PromiseA+2.3.3
                then.call(x,(y)=>{
                    // PromiseA+ 2.3.3.1
                    if(used)return;
                    used = true;
                    resolvePromise(promise2,y,resolve,reject);
                },(r)=>{
                    //PromiseA+2.3.3.2
                    if(used)return;
                    used = true;
                    reject(r)
                });
            }else{
                //PromiseA+ 2.3.3.4
                if(used)return;
                used = true;
                reject(x);
            }
        }catch(e){
            //PromiseA+ 2.3.3.2
            if(used)return;
            used = true;
            reject(e);
        }
    }else{
        //PromiseA+ 2.3.3.4
        resolve(x);
    }
}
module.exports = Promise;

我们可以用专门的测试脚本测试所编写的代码是否符合PromiseA+的规范。
在上面的promise实现的代码中,增加一下代码

Promise.defer = Promise.deferred = function(){
    let dfd = {};
    dfd.promise = new Promise((resolve,reject)=>{
        dfd.resolve = resolve;
        dfd.reject = reject;
    });
    return dfd;
}

安装测试脚本

npm install -g promises-aplus-tests

如果当前的promise源码的文件名为promise.js

那么在对应的目录执行以下命令:

promises-aplus-tests promise.js

promises-aplus-tests*有872条测试用例。以上代码,可以完美通过所有用例。

本文借鉴自:https://blog.csdn.net/liuyan19891230/article/details/88385973

上一篇:Javascript异步解决方案总结


下一篇:使用JS调用手机本地摄像头或者相册图片识别二维码/条形码