欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

实现一个promise

程序员文章站 2022-07-03 09:32:08
...
在大前端,越来越人来探究promise背后的真面目,今天我们就来实现一个符合promiseA+规范的promise。promise上的静态方法有resolve()、reject()、all()、race(),原型上的方法有then()、catch()、finally()。

1、基础框架

promiser的构造函数接收一个参数是executor函数,并且传入两个参数:resolve,reject。分别是异步操作成功的回调函数和异步操作失败后的回调函数。

promise有三个状态 等待(pending) 成功态 (fulfilled) 失败态(rejected)

默认情况是 pending ->  fulfilled
          pending ->  rejected 
          fulfilled不能和rejected相互转化复制代码

下面来看一下代码具体的实现:

function Promise(executor){  
    let self = this;  
    self.status = 'pending'  
    self.value = undefined;  
    self.reason = undefined;  
    self.onResolvedCallbacks = []; //异步时,存放成功的回调函数  
    self.onRejectedCallbacks = []; //异步时,存放失败的回调函数  
    // 只有状态是pending 参能进行状态的转化  
    function resolve(value) {    
        if(self.status === 'pending'){      
            self.value = value;      
            self.status = 'fulfilled';      
            self.onResolvedCallbacks.forEach(function (fn) {        
                fn(); //成功时调用循环调用成功的函数执行      
            });   
         } 
    }  
    function reject(reason) {    
        if(self.status === 'pending'){      
            self.reason = reason;      
            self.status = 'rejected';      
            self.onRejectedCallbacks.forEach(function (fn) {        
                fn();//失败时调用循环调用失败的函数执行      
            })    
        }  
    }  
    try{    
        executor(resolve, reject); // 如果执行这个executor执行时候抛出异常 应该走下一个then的失败  
    }catch(e){    
        reject(e);// 出错了   
    }
}复制代码

2、then方法

每个promise实例上都有一个then方法,then方法接受两个参数,onFulfilled和onRejected。判断状态成功的时候(fulfilled),调用onFulfilled函数,把成功的值传回。判断状态失败的时候(rejected),调用onRejected失败函数,把失败的值传回。

如果状态是pending,代表是异步执行,把onFulfilled和onRejected函数存起来,executor里resolve函数和reject函数执行的时候再调用。

Promise.prototype.then = function (onFulfilled, onRejected) {  
    let self = this;  
    if (self.status === 'fulfilled'){    
        onFulfilled(self.value);  
    }  
    if (self.status === 'rejected'){    
        onRejected(self.reason); 
    }  
    if( self.status === 'pending'){    
        //异步的实现    
        self.onResolvedCallbacks.push(function () {      
            onFulfilled(self.value);    
        });    
        self.onRejectedCallbacks.push(function () {      
            onRejected(self.reason);    
        })  
    }}
复制代码

3、then方法链式调用

  • promise每次调用then后,返回一个新的promise(then方法成功后 返回的是一个新的promise,这个返回的promise会被执行,如果返回的promise是成功的,会把这个结果传递到外层的下一个then中)
  • 如果返回的是promise 用promise的成功或者失败 执行下一个then
  • 如果返回的是一个普通值 会走外层下一个then的成功
  • 如果执行的时候 抛出异常就会走到下一个次then中的失败
  • then中可以不传递参数,如果不传递 会透到下一个then中
Promise.prototype.then = function (onFulfilled, onRejected) {  
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled:function (data) {    return data  }  
    onRejected = typeof onRejected === 'function' ? onRejected:function (err) {    throw err;  }  
    let self = this;  
    let promise2; //promise2就是我们每次调用then后返回的新的promise
    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);        
                }      
            }, 0);    
        }    
        if (self.status === 'rejected') {      
            setTimeout(() => {        
               try{          
                    let x = onRejected(self.reason);          
                    resolvePromise(promise2, x, resolve, reject);        
                    }catch(e){          
                    reject(e)        
                }      
            },0)    
        }    
        if (self.status === 'pending') {      
            // 默认当前 new Promise  executor中是有异步的      
            self.onResolvedCallbacks.push(function () {        
                setTimeout(() => {          
                    try{            
                        let x = onFulfilled(self.value);            
                        resolvePromise(promise2, x, resolve, reject);          
                    }catch(e){            
                        reject(e)          
                    }        
                }, 0);      
             });    
            self.onRejectedCallbacks.push(function () {        
                setTimeout(() => {          
                    try{           
                        let x = onRejected(self.reason);            
                        resolvePromise(promise2, x, resolve, reject);          
                    }catch(e){
                        reject(e);          
                    }        
                }, 0);      
            })    
        }  
    });  
    return promise2;  
}复制代码

4、链式调用的核心方法

核心方法,处理成功或者失败执行的返回值和promise2的关系

function resolvePromise(promise2,x,resolve,reject) {  
    // 这个处理函数 需要处理的逻辑韩式很复杂的  
    // 有可能这个x 是一个promise  但是这个promise并不是我自己的  
    if(promise2 === x){   
        return reject(new TypeError('TypeError: Chaining cycle detected for promise #<Promise>'))  
    }  
    // 不单单需要考虑自己 还要考虑 有可能是别人的promise  let called; 
    // 文档要求 一旦成功了 不能调用失败  
    if((x!=null&&typeof x=== 'object') || typeof x === 'function'){    
        // 这样只能说 x 可能是一个promise    
        try{      
            // x = {then:function(){}}    
            let then = x.then; // 取then方法      
            if(typeof then === 'function'){        
                then.call(x,function (y) { 
                    // resolve(new Promise)          
                    if(!called){called = true;} else{ return;}          
                    resolvePromise(x,y,resolve,reject); //  递归检查promise        
                },function (r) {          
                    if (!called) { called = true; } else { return; }          
                        reject(r);        
                });      
            }else{ // then方法不存在        
                resolve(x); // 普通值      
            }    
        }catch(e){ // 如果取then方法出错了,就走失败      
            if (!called) { called = true; } else { return; }      
            reject(e);    
        }  
    }else{    
        resolve(x);  
    }
}复制代码

5、catch方法的实现

catch方法其实就是then方法,直接调用then方法,成功传null,失败把参数传进去就ok了。

Promise.prototype.catch = function (onRejected) {  
    return this.then(null, onRejected);
}复制代码

6、finally方法

无论成功还是失败,都要执行回调函数,并且把成功或者失败的值向下传递。

Promise.prototype.finally = function (cb) {   
    return this.then(function (data) {    
        cb();    
        return data;  
    }, function (err) {
        cb();    
        throw err;  
    });
}复制代码

7、reject方法实现

Promise.reject = function (reason) {  
    return new Promise(function (resolve, reject) {    
        reject(reason);  
    })
}复制代码

8、resolve方法实现

Promise.resolve = function (value) {  
    return new Promise(function (resolve, reject) {    
        resolve(value);  
    })
}复制代码

9、all方法实现

Promise提供了一个 并发的方法 Promise.all 实现并发执行promise.all方法返回的结果是一个promise

Promise.all = function (promises) {  
    return new Promise(function (resolve, reject) {    
        let arr = [];    // 处理数据的方法    
        let i = 0;    
        function processData(index, data) {      
            arr[index] = data; //数组的索引和长度的关系      
            if (++i === promises.length) { 
                // 当数组的长度 和promise的个数相等时 说明所有的promise都执行完成了        
                resolve(arr);      
            }    
        }    
        for (let i = 0; i < promises.length; i++) {      
            let promise = promises[i];      
            if (typeof promise.then == 'function') {       
                promise.then(function (data) {          
                    processData(i, data); // 把索引和数据 对应起来 方便使用        
                }, reject)      
            } else {        
                processData(i, promise);      
            }    
        }  
    });
}复制代码

10、race方法实现

Promise.race传一个数组过去,只返回一个结果,哪个快返回哪个。

Promise.race = function (promises) {  
    return new Promise(function (resolve, reject) {    
        for (let i = 0; i < promises.length; i++) {      
            let promise = promises[i];      
            if (typeof promise.then == 'function') {        
                promise.then(resolve, reject)      
            } else {        
                resolve(promise);      
            }    
        }  
    })
}复制代码