对Promise的理解

对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的理解)