Promise-resolve流程源碼剖析

原文連接:連接javascript

1 最簡單一個案例

function runAsync(){
  let p = new Promise(function(resolve,reject){
    console.log('exec');
    setTimeout(function(){
      resolve('someData');
    },2000);
  });
  return  p;
}
var promise = runAsync();
promise.then(function(data){
  console.log(data);
});
console.log('同步執行');
console.log(promise);

控制檯輸出java

exec
同步執行
Promise
//兩秒後
someData

2 Promise內部是如何運行的?

2.1 執行這行代碼的時候:let p = new Promise(f);

function noop() {}
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;
  //注意這裏,若是fn傳入的是noop這個函數,那麼不會執行doResolve
  if (fn === noop) return;
  doResolve(fn, this);
}
Promise._onHandle = null;
Promise._onReject = null;
Promise._noop = noop;
function doResolve(fn, promise) {
  var done = false;
  var res = tryCallTwo(fn, function (value) {
    if (done) return;
    done = true;
    resolve(promise, value);
  }, function (reason) {
    if (done) return;
    done = true;
    reject(promise, reason);
  });
  if (!done && res === IS_ERROR) {
    done = true;
    reject(promise, LAST_ERROR);
  }
}
function tryCallTwo(fn, a, b) {
  try {
    fn(a, b);
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}

能夠看到 let p = new Promise( f );在 傳入的 f. 函數不是noop的時候,git

  • 第一會先執行 f 函數
  • 第二生成一個Promise對象
p =>{
  _deferredState:0,//deffer的狀態,表明的應該是 _deferreds 的類型,1 是 single,2 是 Array
  _state:0,//每一個promise對象的狀態維護標識
  _value:null,//resolve函數執行的時候,異步獲得的結果
  _deferreds:null  
}

2.2執行這行代碼的時候: promise.then(function(data){ console.log(data);});

Promise.prototype.then = function(onFulfilled, onRejected) {
  if (this.constructor !== Promise) {//這些比較的都是引用地址;
    return safeThen(this, onFulfilled, onRejected);
  }
  var res = new Promise(noop);
  handle(this, new Handler(onFulfilled, onRejected, res));
  //注意這裏 then的鏈式調用,每次then函數執行完畢以後,返回值都是一個新的Promise實例對象,
  return res;
};
//這裏生成一個deffer對象,保存then函數中註冊的onFulfilled和onRejected回調,以及要返回的新的promise實例對象
function Handler(onFulfilled, onRejected, promise){
  this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
  this.onRejected = typeof onRejected === 'function' ? onRejected : null;
  this.promise = promise;
}
function handle(self, deferred) {
  //不會進入這裏
  while (self._state === 3) {
    self = self._value;
  }
  //也不會進入這裏
  if (Promise._onHandle) {
    Promise._onHandle(self);
  }
  //進入這裏,注意這裏,若是經過then的鏈式調用,那麼每次then返回的對象都是一個新的相似於下面 p 實例對象;
  if (self._state === 0) {
    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(self, deferred);
}

此時再來看下p這個promise實例的屬性值github

p =>{
  _deferredState:1,//deffer的狀態
  _state:0,//每一個promise對象的狀態維護標識
  _value:null,//resolve函數執行的時候,異步獲得的結果
  _deferreds: new Handler(onFulfilled, onRejected, res)//存放經過then註冊的函數以及返回的❤️Promise實例對象的一個Handler對象;
}
res:{
  _deferredState:0,//deffereds的狀態,
  _state:0,//每一個promise對象的狀態維護標識
  _value:null,//resolve函數執行的時候,異步獲得的結果
  _deferreds:null  
}

若是返回的res在執行then方法,那麼c#

p =>{
  _deferredState:1,//deffer的狀態
  _state:0,//每一個promise對象的狀態維護標識
  _value:null,//resolve函數執行的時候,異步獲得的結果
  _deferreds: new Handler(onFulfilled, onRejected, res)//存放經過then註冊的函數以及返回的❤️Promise實例對象的一個Handler對象;
}
res:{
  _deferredState:1,//deffereds的狀態,
  _state:0,//每一個promise對象的狀態維護標識
  _value:null,//resolve函數執行的時候,異步獲得的結果
  _deferreds:new Handler(onFulfilled, onRejected, res)//存放經過then註冊的函數以及返回的❤️Promise實例對象的一個Handler對象; 
}

2.3 異步操做完成之後:resolve('someData');

//真正調用這個函數的是tryCallTwo中的第二個函數入參;self就是p這個promise實例對象;
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 (
    //好比resolve(p1)   p1是一個新的promise對象;
    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;
      self._value = newValue;
      finale(self);
      return;
    } else if (typeof then === 'function') {
      doResolve(then.bind(newValue), self);
      return;
    }
  }
  //對於簡單的返回值,好比後臺返回的JSON字符串等,這裏就直接進行處理;
  self._state = 1;//fulfilled
  self._value = newValue;//給這個promise對象添加屬性值 _value,用來保存異步操做的結果;
  finale(self);//最後處理這個promise對象
}

此時的promise實例對象,關注對比p這個實例對象的變化,能夠看到resolve以後,至關於將異步的結果給到了p這個Promise實例對象的_value屬性值,同時改變這個p的狀態_state爲1 ==> fulfilledpromise

p =>{
  _deferredState:1,//deffer的狀態
  _state:1,//每一個promise對象的狀態維護標識
  _value:'someData',//resolve函數執行的時候,異步獲得的結果
  _deferreds: new Handler(onFulfilled, onRejected, res)
}

2.4 finale(self);//最後處理這個promise對象

function finale(self) {
  //進入這個if語句
  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;
  }
}
function handle(self, deferred) {
  while (self._state === 3) {
    self = self._value;
  }
  if (Promise._onHandle) {
    Promise._onHandle(self);
  }
  //此時不會進入這裏由於 _state的值爲 1 
  if (self._state === 0) {
    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 fulfilled. 2  rejected 的時候纔會執行
  handleResolved(self, deferred);
}
function handleResolved(self, deferred) {
  asap(function() {
    //獲得promise.then(function(data){ console.log(data);});註冊的函數
    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;
    }
    //執行then中註冊回調函數
    var ret = tryCallOne(cb, self._value);
    if (ret === IS_ERROR) {
      reject(deferred.promise, LAST_ERROR);
    } else {
      resolve(deferred.promise, ret);
    }
  });
};
function tryCallOne(fn, a) {
  try {
    return fn(a);
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}

至此一個簡單的promsie的實現流程完畢;異步

下面用實際的例子來看下:函數

3 對於then的鏈式調用,Promise內部又是如何運行的呢?

下一個then中註冊的函數會接收到上一個then的返回值做爲該then中註冊的函數的參數;

3.1 then註冊的函數返回基本數據類型

function runAsync(){
  let p = new Promise(function(resolve,reject){
    console.log('exec');
    setTimeout(function(){
      resolve('someData');
    },2000);
  });
  return  p;
}
var promise = runAsync();
promise.then(function(data){
  console.log(data);
  return 'someData1'
}).then(function(data){
  console.log(data);
  return 'someData2'
}).then(function(data){
  console.log(data)
})
console.log('同步執行');
console.log(promise);

控制檯輸出oop

exec
同步執行
Promise
//兩秒後
someData
someData1
someData2

resolve(deferred.promise, ret);中的ret值就是then中註冊函數的返回值,這裏就是一些簡單的字符串'someData1' 'someData2'this

promise實例對象==> 異步成功 ==> 該實例對象的resolve(data) ==> 
//newValue爲異步獲得的數據,第一次是'someData'這個字符串,下一次就是then中註冊函數的返回值ret,仍是字符串'someData1' 'someData2' 
resolve(self,newValue)     ==>            <== == == == ==  == ==  ||
                                                                ^
==>handle(self,deffer)                                             ||
                                                                ^    
==>handleResolved處理then中註冊的函數;                              ||
                                                                ^
==>接着處理下一個promis==>resolve(deferred.promise, ret);    ===> ||
var p = {
        _deferredState:1,//deffer的狀態
        _state:0,//每一個promise對象的狀態維護標識
        _value:null,//resolve函數執行的時候,異步獲得的結果
        _deferreds:{ 
            onFulfilled:onFulfilled,
            onRejected:onRejected,
            promise:{//這裏是  new Promise(noop)
                _deferredState:1,
                _state:0,
                _value:null,
                _deferreds:{//經過then註冊的執行對象
                    onFulfilled:onFulfilled,
                    onRejected:onRejected,
                    promise:{//這裏是  new Promise(noop)
                        _deferredState:1,
                        _state:0,
                        _value:null,
                        _deferreds:{//經過then註冊的執行對象
                            onFulfilled:onFulfilled,
                            onRejected:onRejected,
                            promise:{//這裏是  new Promise(noop)
                                _deferredState:1
                                _state:0,
                                _value:null,
                                _deferreds:null
                            },
                        }
                    }
                }
            }
        }
    };

3.2 then註冊的函數返回一個新的promise

function runAsync(){
  let p = new Promise(function(resolve,reject){
    console.log('exec');
    setTimeout(function(){
      resolve('someData');
    },2000);
  });
  return  p;
};
function runAsync1(){
  return new Promise(function(resolve,reject){
    setTimeout(function(){
      resolve('someData1');
    },2000);
  })
};
function runAsync2(){
  return new Promise(function(resolve,reject){
    setTimeout(function(){
      resolve('someData2');
    },2000);
  })
};
//如下的異步操做會按照順序進行執行;
var promise = runAsync();
promise.then(function(data){
  console.log(data);
  return runAsync1()
}).then(function(data){
  console.log(data);
  return runAsync2()
}).then(function(data){
  console.log(data);
  // return 'someData3'
})
console.log('同步執行');
console.log(promise);

控制檯輸出

exec
同步執行
Promise
//兩秒後
someData
//兩秒後
someData1
//兩秒後
someData2
promise實例對象 ==> 異步成功 ==> 該實例對象的resolve(data) ==> 
//newValue爲異步獲得的數據,這裏第一次是 'someData'這個字符串,下一次就是then中註冊函數的返回值,這裏就是runAsync返回的promise對象
resolve(self,newValue)    ==>            <== == == == ==  == ==  ||
                                                                ^
==>handle(self,deffer)                                             ||
                                                                ^
==>handleResolved處理then中註冊的函數;                              ||
                                                                ^
==>接着處理下一個promise==>resolve(deferred.promise, ret);    ===> ||

整個promise鏈以下

var p = {
        _deferredState:1,//deffer的狀態
        _state:0,//每一個promise對象的狀態維護標識
        _value:null,//resolve函數執行的時候,異步獲得的結果
        _deferreds:{ 
            onFulfilled:onFulfilled,
            onRejected:onRejected,
            promise:{ //經過引用的地址改變,這裏是runAsync返回的promise
                _deferredState:1,
                _state:0,
                _value:null,
                _deferreds:{//因爲runAsync中沒有執行then註冊,這裏將new Promise(noop) 經過then註冊的對象引用拿到;
                    onFulfilled:onFulfilled,
                    onRejected:onRejected,
                    promise:{//經過引用的地址改變,這裏是runAsync返回的promise
                        _deferredState:1,
                        _state:0,
                        _value:null,
                        _deferreds:{
                            onFulfilled:onFulfilled,
                            onRejected:onRejected,
                            promise:{//經過引用的地址改變,這裏是runAsync返回的promise
                                _deferredState:1,
                                _state:0,
                                _value:null,
                                _deferreds:null
                            },
                        }
                    }
                }
            }
        }
    }

3.3 以上二者有何差別?

  • 相同點:每一個then返回的新的promise對象是同樣的,都是經過then函數中的定義的返回值:var res = new Promise(noop);
  • 不一樣點:在handleResolved中,resolve(deferred.promise, ret);中的ret的值不一樣,ret就是每一個then中註冊的函數的返回值,對比以上兩種狀況,一個返回基本數據類型,一個返回Promise對象,接下來重點看下then中註冊的函數返回promise對象的狀況(注意這個和then鏈式調用的promise對象不是一個)
// resolve(deferred.promise, ret);注意這個self,傳入的是deferred這個對象中promise這個引用地址;
//真正調用這個函數的是tryCallTwo中的第二個函數入參;self就是p這個promise實例對象;
function resolve(self, newValue) {
  //此時的newValue是then中註冊函數的返回的Promise實例對象
  //self是deferred.promise
  // 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.')
    );
  }
  //注意,對於then中註冊的函數返回值是一個新的promise對象的時候,此時會進入這裏
  if (
    //好比resolve(p1)   p1是一個新的promise對象;
    newValue &&
    (typeof newValue === 'object' || typeof newValue === 'function')
  ) {
    var then = getThen(newValue);
    if (then === IS_ERROR) {
      return reject(self, LAST_ERROR);
    }
    if (
      //兩個Promise對象原型鏈上都是引用的then這個函數地址
      then === self.then &&
      newValue instanceof Promise
    ) {
      self._state = 3;
      self._value = newValue;
      finale(self);
      //執行到這裏,結束;
      return;
    } else if (typeof then === 'function') {
      doResolve(then.bind(newValue), self);
      return;
    }
  }
//對於then中註冊的函數返回一個promise對象的狀況,下面就不會執行
  self._state = 1;
  self._value = newValue;
  finale(self);
}

self ==> deferred.promise

function finale(self) {
  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;
  }
}

注意在這裏經過對promise鏈進行引用的改變,從而使異步的執行看起來和同步是同樣的;

handle函數有兩個做用,

  • 第一:改變promise鏈的引用,將本來返回的 new Promsie(noop) 改成ret(then中註冊函數返回的promise)
  • 第二:將本來new Promsie(noop) 上面經過then註冊deferred對象,給到ret響應的屬性
function handle(self, deferred) {
  while (self._state === 3) {
    //這裏一直循環直到取到咱們返回的promsie對象,也就是上面的ret,即每一個runAsync函數的返回值;
    self = self._value;
  }
  if (Promise._onHandle) {
    Promise._onHandle(self);
  }
  //將runAsync的返回的promise對象中_deferredState設置爲 1;
  if (self._state === 0) {
    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;
  }
  handleResolved(self, deferred);
}

4 綜合練習

對於註釋的代碼能夠來回切換,看下結果。

function runAsync(){
  let p = new Promise(function(resolve,reject){
    console.log('exec');
    setTimeout(function(){
      resolve('someData');
    },2000);
  });
  return  p;
};
function runAsync1(){
  return new Promise(function(resolve,reject){
    setTimeout(function(){
      console.log('異步1')
      // resolve('someData1');
      reject('error1')
    },2000);
  })
};
function runAsync2(){
  return new Promise(function(resolve,reject){
    setTimeout(function(){
      console.log('異步2')
      // resolve('someData2');
      reject('error2')
    },2000);
  })
}
var promise = runAsync();
promise.then(function(data){
  console.log(data);
  return runAsync1()
}).then(function(data){
  console.log(data);
  return runAsync2()
}).then(function(data){
  console.log(data);
  // return 'someData3'
}).catch(function(error){
  console.log(error)
})
console.log('同步執行');
console.log(promise);
相關文章
相關標籤/搜索