基于promise /A+规范手写promise

2,300 阅读3分钟

什么是promise

promise是一个类,是现在比较常用的一个异步解决方案,用来解决之前异步编程的回调地狱问题

常见的几种异步编程方法

  • 回掉函数
  • 事件监听
  • 发布订阅
  • promise
  • generator(一般不用)
  • async、await(es8语法)

promise和回调函数对比

promise版
let api = new Promise((resolve,reject)=>{
    
    resolve("成功");
    reject("失败")
})

api
.then(val=>{
    resolve(val)
})
.then(val=>{
    resolve(val)
})
.then(val=>{
    console.log(val)  // 成功
})

使用回调函数
$.get(url, data1 => {
    console.log(data1)
    $.get(data1.url, data2 => {
        console.log(data1)
    })
})



这样看起来是不是更加清晰了

promise的使用

  • Promise 是一个构造函数, new Promise 返回一个 promise对象 接收一个excutor执行函数作为参数, excutor有两个函数类型形参resolve reject
// excutor函数会立即执行,参数是resolve和reject函数
// 每个promise实例都有一个then方法
let promise = new Promise(function(resolve,reject){//excutor
    resolve("成功");
    reject("失败")
})

//onfulfilled 成功, onrejectd 失败
promise.then(function(val){  //onfulfilled
    console.log(val) //成功
},function(err){  //onrejectd 
    console.log(err) //失败
})

promise有三个状态

  • pendding 等待状态、resolved 成功态、rejected 失败态

1.pendding 等待状态 -> resolved 成功态
2.pendding 等待状态 -> resolved 成功态

**注意:成功态和失败态不能相互转化,只能由 pending => fulfilled/rejected, 一旦修改就不能再变

promise对象方法**

手写promise代码

function Promise(executor){
    // promise 有三个状态 pending  fulfilled rejected
    this.status = 'pending'; // 初始状态
    this.value = undefined;  // 成功状态时 返回的信息
    this.reason = undefined; // 失败状态时 返回的信息
    let self = this;
    self.onResolveCallbacks = []; // 存储成功状态对应的onFulfilled函数
    self.onRejectedCallbacks = []; // 存储失败状态对应的onRejected函数
    function reoslve(value){ // 变成成功态
        if(self.status === 'pending'){
            self.value = value;
            self.status = 'fulfilled';
            self.onResolveCallbacks.forEach(fn=>fn())
        }
    }
    function reject(reason){ // 变成是失败态
        if(self.status === 'pending'){
            self.reason = reason;
            self.status = 'rejected';
            self.onRejectedCallbacks.forEach(fn=>fn())
        }
    }
    try{
        executor(reoslve,reject);
    }catch(e){
        reject(e);
    }
}
// 这个方法要兼容别人的promise  严谨一些  这个方法 要兼容别人的promise 
function resolvePromise(promise2,x,resolve,reject){
    if(promise2 === x){ // 防止返回的promise 和 then方法返回的promise 是同一个
        return reject(new TypeError('循环引用'));
    }
    if(x!== null && (typeof x === 'object' || typeof x === 'function')){ // {}
        let called;
        try{
            let then = x.then;  // 看看这个对象有没有then方法,如果有 说明x是promise   {then:undefined}
            if(typeof then === 'function'){  
                then.call(x,y=>{
                    if(called) return
                    called = true;
                    // 如果返回的是一个promise这个promise,resolve的结果可能还是一个promise,递归解析直到这个y是一个常量为止
                    resolvePromise(promise2,y,resolve,reject)
                },r=>{
                    if(called) return // 防止调用失败 又调用成功
                    called = true;
                    reject(r);
                });
            }else{ 
                resolve(x); // {then:{}} {then:123}
            }
        }catch(e){ // 这个then方法 是通过 ObjectDefineProperty定义的
            if(called) return
            called = true; // 这个判断为了防止出错后 继续要调用成功逻辑
            reject(e);
        }
    }else{
        resolve(x); // x就是普通常量
    }
}
Promise.prototype.then = function(onfulfilled,onrejected){
    // 参数的可选
    onfulfilled = typeof onfulfilled ==='function'?onfulfilled :val=>val;
    onrejected = typeof onrejected == 'function'?onrejected :err=>{throw err}
    let self = this;
    // 每个promise必须返回一个新的状态 保证可以链式调用
    let promise2 = new Promise(function(resolve,reject){
        if(self.status === 'fulfilled'){ 
            setTimeout(()=>{
                try{
                    let x = onfulfilled(self.value);
                    resolvePromise(promise2,x,resolve,reject)
                }catch(e){
                    reject(e);
                }
            })
        }
        if(self.status === 'rejected'){
            setTimeout(()=>{
                try{
                    let x = onrejected(self.reason);
                    resolvePromise(promise2,x,resolve,reject)
                }catch(e){
                    reject(e);
                }
            })
        }
        if(self.status === 'pending'){
            self.onResolveCallbacks.push(function(){ 
                setTimeout(()=>{
                    try{
                        let x = onfulfilled(self.value);
                        resolvePromise(promise2,x,resolve,reject)
                    }catch(e){
                        reject(e);
                    }
                })
            });
            self.onRejectedCallbacks.push(function(){
                setTimeout(()=>{
                    try{
                        let x = onrejected(self.reason);
                        resolvePromise(promise2,x,resolve,reject)
                    }catch(e){
                        reject(e);
                    }
                })
            })
        }
    });
    return promise2
}

// npm install promises-aplus-tests -g
// promises-aplus-tests promise.js
Promise.deferred = function(){
    let dfd = {};
    dfd.promise = new Promise((resolve,reject)=>{
        dfd.resolve = resolve;
        dfd.reject = reject;
    });
    return dfd;
};
module.exports = Promise