美文网首页
对Promise的理解

对Promise的理解

作者: 充满正能量的灰灰 | 来源:发表于2018-10-16 11:14 被阅读0次

    对Promise的理解,主要是对Promise源代码分析展开(附上github链接https://github.com/then/promise):
    Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的Promise对象。
    先来看个简单例子:

    var pro = new Promise(function(res,rej){
        setTimeout(function(){
            console.log('1s execute...');
            res(1)
        },1000)
    })
    .then(function(n){
        console.log(n)
     })
    

    从上面例子可以看出,promise接受一个函数,这个函数接受2个参数,分别负责来实现异步行为之后的回调操作。
    接下来,我们来看看源代码:

    function Promise(fn) {
      if (typeof this !== 'object') {
        throw new TypeError('Promises must be constructed via new');
      }
      if (typeof fn !== 'function') {
        throw new TypeError('Promise constructor\'s argument is not a function');
      }
      this._deferredState = 0;
      this._state = 0;
      this._value = null;
      this._deferreds = null;
      if (fn === noop) return;
      doResolve(fn, this);
    }
    

    上面这部分代码其实就是接受函数,并执行promise里面传的参数,重点在doResolve这个方法,看这个方法之前先看3个基本的工具方法:

    //  获取某个对象的then属性
    function getThen(obj) {
      try {
        return obj.then;
      } catch (ex) {
        LAST_ERROR = ex;
        return IS_ERROR;
      }
    }
    //  执行调用fn,并传入一个参数
    function tryCallOne(fn, a) {
      try {
        return fn(a);
      } catch (ex) {
        LAST_ERROR = ex;
        return IS_ERROR;
      }
    }
    //  执行调用fn,并传入两个参数
    function tryCallTwo(fn, a, b) {
      try {
        fn(a, b);
      } catch (ex) {
        LAST_ERROR = ex;
        return IS_ERROR;
      }
    }
    

    这时候,再来看一下doResolve这个方法:

    function doResolve(fn, promise) {
      var done = false;
      var res = tryCallTwo(fn, function (value) {
        if (done) return;
        done = true;
        resolve(promise, value);//   将当前promise和resolve 的value传进去
      }, function (reason) {
        if (done) return;
        done = true;
        reject(promise, reason);
      });
      if (!done && res === IS_ERROR) {
        done = true;
        reject(promise, LAST_ERROR);
      }
    }
    

    这个方法主要就是执行了新建promise对象时候传的函数,我们仔细看第2、3个参数,这2个函数执行的时候,会分别进入resolve和reject方法里面,我们以resolve为例,来看看内部的resolve干了什么:

    function resolve(self, newValue) {
      // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
      if (newValue === self) {
        return reject(
          self,
          new TypeError('A promise cannot be resolved with itself.')
        );
      }
      if (
        newValue &&
        (typeof newValue === 'object' || typeof newValue === 'function')
      ) {
        var then = getThen(newValue);
        if (then === IS_ERROR) {
          return reject(self, LAST_ERROR);
        }
        if (
          then === self.then &&
          newValue instanceof Promise
        ) {
          self._state = 3;  //  如果value本身是一个promise对象,则状态跟着这个promise走
          self._value = newValue;
          finale(self);
          return;
        } else if (typeof then === 'function') {   //  如果value是一个带then函数的对象,则继续走doResolve(基于then函数)
          doResolve(then.bind(newValue), self);
          return;
        }
      }
    //  如果value没啥特殊的,就走正常程序
      self._state = 1; //  state变为1
      self._value = newValue; 
      finale(self);
    }
    

    我们顺着最简单的情况看流程哈,因为任何特殊情况,走到最后都是最简单的情况。这样,接着看finale函数:

    function finale(self) {
      //  简单意思便是:一个一个执行promise对象队列中的deferreds
      if (self._deferredState === 1) {
        handle(self, self._deferreds);
        self._deferreds = null;
      }
      if (self._deferredState === 2) {
        for (var i = 0; i < self._deferreds.length; i++) {
          handle(self, self._deferreds[i]);
        }
        self._deferreds = null;
      }
    }
    

    怎么突然冒出来个_deferreds来了呢,其实_deferreds可以理解为当前异步执行队列中的处理器,那么它的赋值是在哪里做的呢?我们来看下promise的then方法的代码:

    Promise.prototype.then = function(onFulfilled, onRejected) {
      if (this.constructor !== Promise) {
        return safeThen(this, onFulfilled, onRejected);
      }
      var res = new Promise(noop);  //  then方法,新建一个promise
      handle(this, new Handler(onFulfilled, onRejected, res));  //  并将新建一个handler,然后再进行处理
      return res;
    };
    
    function safeThen(self, onFulfilled, onRejected) {
      return new self.constructor(function (resolve, reject) {
        var res = new Promise(noop);
        res.then(resolve, reject);
        handle(self, new Handler(onFulfilled, onRejected, res));
      });
    }
    

    我们先来看下Handler构造函数干了啥:

    function Handler(onFulfilled, onRejected, promise){
      this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
      this.onRejected = typeof onRejected === 'function' ? onRejected : null;
      this.promise = promise;
    //  新建了一个对象,promise属性存储当前传进来的promise对象,onfulfilled/onRejected分别存储then方法传进来的回调函数
    }
    

    这样,结合上面,我们可以发现then的时候,将对应的handler放到了handle方法中去处理,我们看看handle方法:

    function handle(self, deferred) {
      while (self._state === 3) {
        //  当state为3的时候,则整个状态依赖于新的那个promise类型的value
        self = self._value;
      }
      if (Promise._onHandle) {
        Promise._onHandle(self);
      }
      if (self._state === 0) {//  当还是0的时候,往_deferreds里面放处理器(也就是then方法执行的逻辑点)
        if (self._deferredState === 0) {
          self._deferredState = 1;
          self._deferreds = deferred;
          return;
        }
        if (self._deferredState === 1) {
          self._deferredState = 2;
          self._deferreds = [self._deferreds, deferred];
          return;
        }
        self._deferreds.push(deferred);
        return;
      }
      //  如果state为1或者2,直接进入handleResolved
      handleResolved(self, deferred);
    }
    

    来看看handleResolved源代码:

    function handleResolved(self, deferred) {
      asap(function() {
        var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;//  根据状态来选择调取的回调函数
        if (cb === null) {
          if (self._state === 1) {
            resolve(deferred.promise, self._value);
          } else {
            reject(deferred.promise, self._value);
          }
          return;
        }
        var ret = tryCallOne(cb, self._value);  //  将值传人回调函数,并返回执行结果
        if (ret === IS_ERROR) {
          reject(deferred.promise, LAST_ERROR);
        } else {
          resolve(deferred.promise, ret);  // 再将当前结果resolve运行到then返回的promise中去 
        }
      });
    }
    

    到此为止,咱们已经把promise的主要核心代码已经分析过一遍了。仔细想想,其实主要就围绕着以下几个关键点展开:
    1、执行传到promise构造函数的函数;
    2、根据then和handle方法结合,将需要处理的handlers放在处理队列之中;
    3、内部实现的resolve和reject方法分别更新当前promise对象的状态;
    4、根据状态来执行对应的处理函数;
    5、循环上述过程。

    下面看几个实际例子来配合理解:

    =========================
    //  例子1:简单传值
    var pro = new Promise(function(res,rej){
         setTimeout(function(){
              console.log('1s execute...')
              res(1)
          },1000)
    });
    pro.then(function(n){
        console.log(n)
    })
    //  例子1输出结果:
    1s execute...
    1
    =========================
    //  例子2: 连续传递,且第1个then方法不返回值
    var pro = new Promise(function(res,rej){
         setTimeout(function(){
              console.log('1s execute...')
              res(1)
          },1000)
    });
    pro.then(function(n){
        console.log(n)
    }).then(function(m){
        console.log(m)
    })
    //  例子2输出结果:
    1s execute...
    1
    undefined
    =========================
    //  例子3:连续传递,且第1个then方法正常返回值
    var pro = new Promise(function(res,rej){
         setTimeout(function(){
              console.log('1s execute...')
              res(1)
          },1000)
    });
    pro.then(function(n){
        console.log(n);
        return 2;
    }).then(function(m){
        console.log(m)
    })
    //  例子3输出结果:
    1s execute...
    1
    2
    =========================
    //  例子4:连续传递,且第1个then方法返回promise,但是不res更改状态,会中断传递
    var pro = new Promise(function(res,rej){
         setTimeout(function(){
              console.log('1s execute...')
              res(1)
          },1000)
    });
    pro.then(function(n){
        console.log(n);
        return new Promise(function(res,rej){
        setTimeout(function(){
        console.log('promise waiting')
        },1000)
        })
    }).then(function(m){
        console.log(m)
    })
    //  例子4输出结果:
    1s execute...
    1
    promise waiting
    =========================
    //  例子5:连续传递,且第1个then方法返回promise,但是不res更改状态,不会中断传递
    var pro = new Promise(function(res,rej){
         setTimeout(function(){
              console.log('1s execute...')
              res(1)
          },1000)
    });
    pro.then(function(n){
        console.log(n);
        return new Promise(function(res,rej){
        setTimeout(function(){
            console.log('promise waiting');
            res('promise 传递');
         },1000)
        })
    }).then(function(m){
        console.log(m)
    })
    //  例子5输出结果:
    1s execute...
    1
    promise waiting
    promise 传递
    

    相关文章

      网友评论

          本文标题:对Promise的理解

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