美文网首页Web 前端开发 前端开发那些事让前端飞
自己造轮子,实现符合 Promise/A+ 规范的Promise

自己造轮子,实现符合 Promise/A+ 规范的Promise

作者: JOKER_HAN | 来源:发表于2018-01-13 19:07 被阅读0次

    1.Promise解决什么问题?

    1.1回到地狱

    比如实现一个动画,页面上有多个球,每个球要等到上一个球的运动停止之后开始动画。

      function move(ball,target,cb){
          let timer = setInterval(function(){
            //先取到当前的left值
           let index=0;
          let timer = setInterval(function () {
            if(index++<target){
              ball.style.transform = `translateX(${index}px)`;
            }else{
              clearInterval(timer);
              resolve();
              cb();
            }
          }, 13)
            }
          },4)
        }
        move(ball1,100,function(){
          move(ball2,100,function(){
            move(ball3,100,function(){
              alert('over');
            });
          });
        });
    

    问题:代码丑陋并且多层嵌套,Promise横空出世可以解决这个问题。下面用Promise进行实现这个动画

    function move(ball, target) {
        return new Promise(function (resolve, reject) {
          let index=0;
          let timer = setInterval(function () {
            if(index++<target){
              ball.style.transform = `translateX(${index}px)`;
            }else{
              clearInterval(timer);
              resolve();
            }
          }, 13)
        });
      }
      move(ball1, 100)
        .then(function () {
          return move(ball2, 100);
        })
        .then(function () {
          return move(ball3, 100);
        })
        .then(function () {
          alert('over');
        })
    

    2.实现Promise

    实现一个符合 Promise/A+ 规范的 MyPromise,并实现 resolve、reject、catch、all、race、deferred等静态方法。

    const PENDING =  'pending';//初始态
    const FULFILLED =  'fulfilled';//初始态
    const REJECTED =  'rejected';//初始态
    

    2.1实现链式写法

    function Promise(executor){
      let self = this;//先缓存当前promise实例
      self.status = PENDING;//设置状态
      //定义存放成功的回调的数组
      self.onResolvedCallbacks = [];
      //定义存放失败回调的数组
      self.onRejectedCallbacks = [];
      //当调用此方法的时候,如果promise状态为pending,的话可以转成成功态,如果已经是成功态或者失败态了,则什么都不做
      //2.1
      function resolve(value){ //2.1.1
        if(value!=null &&value.then&&typeof value.then == 'function'){
          return value.then(resolve,reject);
        }
        //如果是初始态,则转成成功态
        setTimeout(function(){
          if(self.status == PENDING){
            self.status = FULFILLED;
            self.value = value;//成功后会得到一个值,这个值不能改
            //调用所有成功的回调
            self.onResolvedCallbacks.forEach(cb=>cb(self.value));
          }
        })
    
      }
      function reject(reason){ //2.1.2
        setTimeout(function(){
          //如果是初始态,则转成失败态
          if(self.status == PENDING){
            self.status = REJECTED;
            self.value = reason;//失败的原因给了value
            self.onRejectedCallbacks.forEach(cb=>cb(self.value));
          }
        });
    
      }
      try{
        //因为此函数执行可能会异常,所以需要捕获,如果出错了,需要用错误 对象reject
        executor(resolve,reject);
      }catch(e){
        //如果这函数执行失败了,则用失败的原因reject这个promise
        reject(e);
      };
    }
    function resolvePromise(promise2,x,resolve,reject){
      if(promise2 === x){
        return reject(new TypeError('循环引用'));
      }
      let called = false;//promise2是否已经resolve 或reject了
      if(x instanceof Promise){
        if(x.status == PENDING){
          x.then(function(y){
            resolvePromise(promise2,y,resolve,reject);
          },reject);
        }else{
          x.then(resolve,reject);
        }
      //x是一个thenable对象或函数,只要有then方法的对象,
      }else if(x!= null &&((typeof x=='object')||(typeof x == 'function'))){
        //当我们的promise和别的promise进行交互,编写这段代码的时候尽量的考虑兼容性,允许别人瞎写
       try{
         let then = x.then;
         if(typeof then == 'function'){
           //有些promise会同时执行成功和失败的回调
           then.call(x,function(y){
             //如果promise2已经成功或失败了,则不会再处理了
              if(called)return;
              called = true;
              resolvePromise(promise2,y,resolve,reject)
           },function(err){
             if(called)return;
             called = true;
             reject(err);
           });
         }else{
           //到此的话x不是一个thenable对象,那直接把它当成值resolve promise2就可以了
           resolve(x);
         }
       }catch(e){
         if(called)return;
         called = true;
         reject(e);
       }
    
      }else{
        //如果X是一个普通 的值,则用x的值去resolve promise2
        resolve(x);
      }
    }
    //onFulfilled 是用来接收promise成功的值或者失败的原因
    Promise.prototype.then = function(onFulfildeled,onRejected){
      //如果成功和失败的回调没有传,则表示这个then没有任何逻辑,只会把值往后抛
      //2.2.1
      onFulfilled = typeof onFulfilled == 'function'?onFulfilled:function(value){return  value};
      onRejected = typeof onRejected == 'function'?onRejected:reason=>{throw reason};
      //如果当前promise状态已经是成功态了,onFulfilled直接取值
      let self = this;
      let promise2;
      if(self.status == FULFILLED){
        return promise2 = new Promise(function(resolve,reject){
          setTimeout(function(){
            try{
              let x =onFulfilled(self.value);
              //如果获取到了返回值x,会走解析promise的过程
              resolvePromise(promise2,x,resolve,reject);
            }catch(e){
              //如果执行成功的回调过程中出错了,用错误原因把promise2 reject
              reject(e);
            }
          })
    
        });
      }
      if(self.status == REJECTED){
        return promise2 = new Promise(function(resolve,reject){
          setTimeout(function(){
            try{
              let x =onRejected(self.value);
              resolvePromise(promise2,x,resolve,reject);
            }catch(e){
              reject(e);
            }
          })
        });
      }
      if(self.status == PENDING){
       return promise2 = new Promise(function(resolve,reject){
         self.onResolvedCallbacks.push(function(){
             try{
               let x =onFulfilled(self.value);
               //如果获取到了返回值x,会走解析promise的过程
               resolvePromise(promise2,x,resolve,reject);
             }catch(e){
               reject(e);
             }
    
         });
         self.onRejectedCallbacks.push(function(){
             try{
               let x =onRejected(self.value);
               resolvePromise(promise2,x,resolve,reject);
             }catch(e){
               reject(e);
             }
         });
       });
      }
    
    }
    

    2.2 Promise.prototype.catch

    //catch原理就是只传失败的回调
    Promise.prototype.catch = function(onRejected){
      this.then(null,onRejected);
    }
    

    2.3 Promise.deferred

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

    2.4 Promise.all

    Promise.all = function(promises){
     return new Promise(function(resolve,reject){
       let done = gen(promises.length,resolve);
       for(let i=0;i<promises.length;i++){
         promises[i].then(function(data){
           done(i,data);
         },reject);
       }
     });
    }
    

    2.5 Promise.race

    Promise.race = function(promises){
      return new Promise(function(resolve,reject){
        for(let i=0;i<promises.length;i++){
          promises[i].then(resolve,reject);
        }
      });
    }
    

    2.6 Promise.resolve

    Promise.resolve = function(value){
      return new Promise(function(resolve){
        resolve(value);
      });
    }
    

    2.7 Promise.reject

    Promise.reject = function(reason){
      return new Promise(function(resolve,reject){
        reject(reason);
      });
    }
    

    参考资料

    相关文章

      网友评论

        本文标题:自己造轮子,实现符合 Promise/A+ 规范的Promise

        本文链接:https://www.haomeiwen.com/subject/rxhpnxtx.html