Promise學習筆記(三):源碼core.js解析(上)

源碼閱讀階段

先理解Promise根本吧,想快點理解的話能夠直接跳到下個標題.這部分根據理解將持續修改.git

Promise(fn)

function noop() {}
/*
空函數,用於判斷傳入Promise構造器的函數是否爲空函數,若是爲空函數構造一個promise對象並初始化狀態爲pending,終值null,回調狀態0和隊列null.
*/
var LAST_ERROR = null;//記錄Promise內部最後的一次錯誤
var IS_ERROR = {}; //空對象,標識表示發生了錯誤
module.exports = Promise; //暴露模塊接口爲Promise
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; //promise狀態
  this._value = null; //resolve返回的結果
  this._deferreds = null;
  if (fn === noop) return;
  doResolve(fn, this); //處理函數
}
Promise._onHandle = null;
Promise._onReject = null;
Promise._noop = noop;

原文中表示將帶有_前綴的變量在構造的時候轉爲(_隨機數)的形式,來混淆和阻止它們被使用.接下來列出說明重要的變量.github

* _defferedState = 0
表示_deferreds的類型,0時表示null,1時表示單個handler(後面講述),2表示多個deferreds(數組)
* _state = 0
promise狀態,0爲pending,1爲fulfilled,2爲rejected,3則爲值已被傳遞給下個promise.
* _value = null
resolve返回的結果,也就是咱們所說的終值/拒因
* _deferreds = null
表示單個或多個handler(後面講述)

doResolve(fn,this)

相比你們都看到這行函數了doResolve(fn, this);,這裏也就是咱們初始化一個Promise時會作的事了,咱們在看這個函數前,先理解下源碼中相似於工具函數同樣的函數.c#

//獲取then方法,沒有then方法標識錯誤
function getThen(obj) {
  try {
    return obj.then;
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}
//內部捕獲錯誤,單個參數函數
function tryCallOne(fn, a) {
  try {
    return fn(a);
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}
//內部捕獲錯誤,兩個參數函數
function tryCallTwo(fn, a, b) {
  try {
    fn(a, b);
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}

接下來咱們直接跳到doResolve(fn,promise)數組

function doResolve(fn, promise) {//傳入參數爲一個函數,一個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);//後續再分析它
  }
}

這就是咱們的doResolve函數,能夠看出,它只是箇中間件,用於幹什麼的呢,就是解決傳入函數error問題並進行reject的.重點是調用了咱們很眼熟的兩個函數,resolve()reject()promise

resolve() and reject()

在這個函數裏咱們找到了兩個新東西,resolve()reject(),看名字就知道這兩個函數是什麼啦,咱們先看reject()函數

function reject(self, newValue) {//兩個參數,從doResolve咱們能夠知道self是一個promise對象,而newValue就是拒因啦
  self._state = 2;//狀態變成rejected了
  self._value = newValue;//promise中結果變爲拒因
  if (Promise._onReject) {//在core.js中它爲null,因此多是用於別的功能.咱們直接跳過
    Promise._onReject(self, newValue);
  }
  finale(self);//新的函數又出現了.
}

reject()函數傳入了promise對象和一個reason拒因,函數作的就是將promise的狀態變爲rejected,並將promise的值進行更改.而後調用finale()函數工具

能夠看到出現了新函數finale(),而且傳了已經進行完reject的promise對象給它.可是咱們仍是先看resolve()oop

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);//獲取值中的then函數
    if (then === IS_ERROR) {//不存在then,reject去
      return reject(self, LAST_ERROR);
    }
    if (//存在而且原來值它是一個promise對象
      then === self.then &&
      newValue instanceof Promise
    ) {//同步兩個promise,將傳入的promise狀態變爲已傳遞並把newValue這個promise對象做爲promise的值,而後finale並退出函數.
      self._state = 3;
      self._value = newValue;
      finale(self);
      return;
    } else if (typeof then === 'function') {//若是獲取到then的值不爲promise,但then是一個函數(thenable)
      doResolve(then.bind(newValue), self);//這裏能夠看看上個博文,對這個狀況有說明,對終值自身進行doResolve取得新的值做爲新的終值.
      return;
    }
  }
  self._state = 1;//promise狀態爲fulfilled
  self._value = newValue;//值傳遞
  finale(self);//finale了
}

resolve()中,咱們照樣是傳進了一個promise對象和value(終值),函數內部經過標準的判斷(詳細參考學習筆記(二):規範),進行[[Resolve]]操做,最後將promise對象狀態變動爲fulfilled並改變其終值,調用finale.學習

finale()

咱們能夠進行finale()的分析了,畢竟咱們的核心函數都指向它呢.this

function finale(self) {//傳入了一個promise對象
  if (self._deferredState === 1) {//判斷deferreds是單個
    handle(self, self._deferreds);//傳入了promise對象和promise對象中的_deferreds
    self._deferreds = null;//讓deferreds爲null
  }
  if (self._deferredState === 2) {//判斷deferreds是數組
    for (var i = 0; i < self._deferreds.length; i++) {
      handle(self, self._deferreds[i]);//傳入了promise對象和promise對象中的_deferreds數組的全部數據
    }
    self._deferreds = null;//讓deferreds爲null
  }
}

很好,這下都是新的東西了,_deferredState這個就是判斷_deferreds是數組仍是單個的狀況,並對其中每個deferred進行handle調用.可是_defferreds又是什麼呢,handle()這個函數又作了什麼處理呢...

handle()

function handle(self, deferred) {//這個傳入參數是預想之中的
  while (self._state === 3) {//promise狀態爲3的時候,也就是該promise已傳遞完畢的時候
    self = self._value;//重定位self爲promise傳遞的值
  }
  if (Promise._onHandle) {//一樣不屬於本篇考慮範疇
    Promise._onHandle(self);
  }
  if (self._state === 0) {//promise狀態爲pending時
    if (self._deferredState === 0) {//沒有deferreds時
      self._deferredState = 1;//deferreds變爲單個
      self._deferreds = deferred;傳入deferreds入列
      return;
    }
    if (self._deferredState === 1) {
      self._deferredState = 2;//deferreds變爲數組
      self._deferreds = [self._deferreds, deferred];//傳入deferred進入數組
      return;
    }
    self._deferreds.push(deferred);//已是數組了就直接push增長
    return;
  }
  handleResolved(self, deferred);//新東西,在state!==0時傳入promise和defered
}

能夠看到其實這個函數在對_deferreds進行添加,進行着_deferreds的修改和寫入,與finale()所作的事情偏偏相反,可是詳細的處理卻仍是在handleResolved()函數裏面.

handleResolved()

function handleResolved(self, deferred) {
  asap(function() {//注意!asap是一個引入的模塊,意思就是as soon as possible,就是儘快執行的意思,咱們不須要考慮它作了什麼.
    // promise狀態是fulfilled狀況下cb爲deferred中的Fulfilled函數,不是的話則爲onRejected函數...
    var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
    if (cb === null) {//若是不存在對應狀態的函數
      if (self._state === 1) {//當前promise對象是否爲fulfilled狀態
        resolve(deferred.promise, self._value);//傳入deferred中保存的promise和當前promise的值進行resolve
      } else {
        reject(deferred.promise, self._value);//與上相似,進行reject
      }
      return;
    }
    var ret = tryCallOne(cb, self._value);//存在則嘗試執行對應函數,返回執行結果(與兩個參數的tryCall不一樣,這裏返回了函數運行結果)
    if (ret === IS_ERROR) {//有錯誤,reject
      reject(deferred.promise, LAST_ERROR);
    } else {//沒錯誤,對deferred.promise用函數返回值進行resolve
      resolve(deferred.promise, ret);
    }
  });
}

這裏咱們看到了deferred是一個保存了promise對象,onFulfilled函數,onRejected函數的對象,至關於一個保存現場.其實這裏就是咱們即將在源碼core.js解析(下)寫到的handler對象了.可是這裏咱們暫且先不深究,知道就行了.
handleResolved()毫無疑問就是在進行着promise的終值傳遞處理,對舊promise對象的狀態修改,並調用resolvereject獲取到值/拒因向下一個Promise傳遞.對這裏的詳細實例分析咱們放到(下)來說.

構造一個Promise時發生了啥?

從簡單看起,咱們構造一個Promise對象的時候通過了哪些函數
先理一下思路.

var A = Promise(function(resolve,reject){
    resolve("ok");
})

這裏面首先是先構造了Promise對象,咱們稱爲A,在構造階段執行了以下代碼.
檢查略....

A._deferredState = 0;
A._state = 0;
A._value = null;
A._deferreds = null;

檢查傳入參數不爲空....

doResolve(function(resolve,reject){
    resolve("ok");
},this);

而後咱們跳到了doResolve()函數處,傳入爲fn,promise

res = tryCallTwo(fn,function(value){resolve(promise, value);},function(reason){reject(promise, reason);});
出錯就reject(promise,LAST_ERROR)

咱們又根據咱們的輸入跳轉到了resolve(promise,value)啦,這裏理一下咱們的函數,promise就是A,value其實就是咱們傳入的"ok".
因此執行的是promise內部中的resolve(promise,"ok")
通過一系列判斷(詳細能夠看規範),咱們的"ok"過五關斬六將直接執行到這一步.

self._state = 1;//A狀態變爲fulfilled
self._value = newValue;//AA終值變爲"ok"

而後咱們finale(self)啦,繼續跳到finale()函數,傳入了A.

//在過程當中咱們的_deferredState始終爲0呀,看了一下
A._deferredState = 0;
//已經沒有什麼好作的了...

咱們的構造已經結束了!這就是咱們new 一個Promise時的過程,跟着思路走,其實加上reject也是一樣的路線而已.

(上)結語

(下)的話我打算重點寫剩餘部分的then函數流程,並儘可能用簡單的語言來描述,但願本身能進一步理解promise,發現有錯漏能及時修訂.

相關文章
相關標籤/搜索