成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

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

wuyangchun / 2728人閱讀

摘要:源碼閱讀階段先理解根本吧想快點(diǎn)理解的話可以直接跳到下個(gè)標(biāo)題這部分根據(jù)理解將持續(xù)修改空函數(shù)用于判斷傳入構(gòu)造器的函數(shù)是否為空函數(shù)如果為空函數(shù)構(gòu)造一個(gè)對象并初始化狀態(tài)為終值回調(diào)狀態(tài)和隊(duì)列記錄內(nèi)部最后的一次錯(cuò)誤空對象標(biāo)識表示發(fā)生了錯(cuò)誤暴露模塊接口為

源碼閱讀階段

先理解Promise根本吧,想快點(diǎn)理解的話可以直接跳到下個(gè)標(biāo)題.這部分根據(jù)理解將持續(xù)修改.

Promise(fn)
function noop() {}
/*
空函數(shù),用于判斷傳入Promise構(gòu)造器的函數(shù)是否為空函數(shù),如果為空函數(shù)構(gòu)造一個(gè)promise對象并初始化狀態(tài)為pending,終值null,回調(diào)狀態(tài)0和隊(duì)列null.
*/
var LAST_ERROR = null;//記錄Promise內(nèi)部最后的一次錯(cuò)誤
var IS_ERROR = {}; //空對象,標(biāo)識表示發(fā)生了錯(cuò)誤
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狀態(tài)
  this._value = null; //resolve返回的結(jié)果
  this._deferreds = null;
  if (fn === noop) return;
  doResolve(fn, this); //處理函數(shù)
}
Promise._onHandle = null;
Promise._onReject = null;
Promise._noop = noop;

原文中表示將帶有_前綴的變量在構(gòu)造的時(shí)候轉(zhuǎn)為(_隨機(jī)數(shù))的形式,來混淆和阻止它們被使用.接下來列出說明重要的變量.

* _defferedState = 0
表示_deferreds的類型,0時(shí)表示null,1時(shí)表示單個(gè)handler(后面講述),2表示多個(gè)deferreds(數(shù)組)
* _state = 0
promise狀態(tài),0為pending,1為fulfilled,2為rejected,3則為值已被傳遞給下個(gè)promise.
* _value = null
resolve返回的結(jié)果,也就是我們所說的終值/拒因
* _deferreds = null
表示單個(gè)或多個(gè)handler(后面講述)
doResolve(fn,this)

相比大家都看到這行函數(shù)了doResolve(fn, this);,這里也就是我們初始化一個(gè)Promise時(shí)會做的事了,我們在看這個(gè)函數(shù)前,先理解下源碼中類似于工具函數(shù)一樣的函數(shù).

//獲取then方法,沒有then方法標(biāo)識錯(cuò)誤
function getThen(obj) {
  try {
    return obj.then;
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}
//內(nèi)部捕獲錯(cuò)誤,單個(gè)參數(shù)函數(shù)
function tryCallOne(fn, a) {
  try {
    return fn(a);
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}
//內(nèi)部捕獲錯(cuò)誤,兩個(gè)參數(shù)函數(shù)
function tryCallTwo(fn, a, b) {
  try {
    fn(a, b);
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}

接下來我們直接跳到doResolve(fn,promise)

function doResolve(fn, promise) {//傳入?yún)?shù)為一個(gè)函數(shù),一個(gè)promise對象
  var done = false; //保證了規(guī)范中提到的一次性
  var res = tryCallTwo(fn, function (value) {//看到了么,用于捕獲錯(cuò)誤.
    if (done) return; //這里不用說了,為了保證兩個(gè)函數(shù)中只有一個(gè)函數(shù)運(yùn)行且僅運(yùn)行一次
    done = true;
    resolve(promise, value);//后續(xù)再分析它
  }, function (reason) {
    if (done) return;
    done = true;
    reject(promise, reason);//后續(xù)再分析它
  });
  if (!done && res === IS_ERROR) {
    done = true;
    reject(promise, LAST_ERROR);//后續(xù)再分析它
  }
}

這就是我們的doResolve函數(shù),可以看出,它只是個(gè)中間件,用于干什么的呢,就是解決傳入函數(shù)error問題并進(jìn)行reject的.重點(diǎn)是調(diào)用了我們很眼熟的兩個(gè)函數(shù),resolve()reject()

resolve() and reject()

在這個(gè)函數(shù)里我們找到了兩個(gè)新東西,resolve()reject(),看名字就知道這兩個(gè)函數(shù)是什么啦,我們先看reject()

function reject(self, newValue) {//兩個(gè)參數(shù),從doResolve我們可以知道self是一個(gè)promise對象,而newValue就是拒因啦
  self._state = 2;//狀態(tài)變成rejected了
  self._value = newValue;//promise中結(jié)果變?yōu)榫芤?  if (Promise._onReject) {//在core.js中它為null,所以可能是用于別的功能.我們直接跳過
    Promise._onReject(self, newValue);
  }
  finale(self);//新的函數(shù)又出現(xiàn)了.
}

reject()函數(shù)傳入了promise對象和一個(gè)reason拒因,函數(shù)做的就是將promise的狀態(tài)變?yōu)?b>rejected,并將promise的值進(jìn)行更改.然后調(diào)用finale()函數(shù)

可以看到出現(xiàn)了新函數(shù)finale(),并且傳了已經(jīng)進(jìn)行完reject的promise對象給它.但是我們還是先看resolve()

function resolve(self, newValue) {
//這里寫的其實(shí)就是按照規(guī)范處理的流程
  /* Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure */
  if (newValue === self) {//傳入值等于自己就拋出錯(cuò)誤
    return reject(
      self,
      new TypeError("A promise cannot be resolved with itself.")
    );
  }
  if (//值為對象或函數(shù)
    newValue &&
    (typeof newValue === "object" || typeof newValue === "function")
  ) {
    var then = getThen(newValue);//獲取值中的then函數(shù)
    if (then === IS_ERROR) {//不存在then,reject去
      return reject(self, LAST_ERROR);
    }
    if (//存在并且原來值它是一個(gè)promise對象
      then === self.then &&
      newValue instanceof Promise
    ) {//同步兩個(gè)promise,將傳入的promise狀態(tài)變?yōu)橐褌鬟f并把newValue這個(gè)promise對象作為promise的值,然后finale并退出函數(shù).
      self._state = 3;
      self._value = newValue;
      finale(self);
      return;
    } else if (typeof then === "function") {//如果獲取到then的值不為promise,但then是一個(gè)函數(shù)(thenable)
      doResolve(then.bind(newValue), self);//這里可以看看上個(gè)博文,對這個(gè)情況有說明,對終值自身進(jìn)行doResolve取得新的值作為新的終值.
      return;
    }
  }
  self._state = 1;//promise狀態(tài)為fulfilled
  self._value = newValue;//值傳遞
  finale(self);//finale了
}

resolve()中,我們照樣是傳進(jìn)了一個(gè)promise對象和value(終值),函數(shù)內(nèi)部通過標(biāo)準(zhǔn)的判斷(詳細(xì)參考學(xué)習(xí)筆記(二):規(guī)范),進(jìn)行[[Resolve]]操作,最后將promise對象狀態(tài)變更為fulfilled并改變其終值,調(diào)用finale.

finale()

我們可以進(jìn)行finale()的分析了,畢竟我們的核心函數(shù)都指向它呢.

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

很好,這下都是新的東西了,_deferredState這個(gè)就是判斷_deferreds是數(shù)組還是單個(gè)的情況,并對其中每一個(gè)deferred進(jìn)行handle調(diào)用.但是_defferreds又是什么呢,handle()這個(gè)函數(shù)又做了什么處理呢...

handle()
function handle(self, deferred) {//這個(gè)傳入?yún)?shù)是預(yù)想之中的
  while (self._state === 3) {//promise狀態(tài)為3的時(shí)候,也就是該promise已傳遞完畢的時(shí)候
    self = self._value;//重定位self為promise傳遞的值
  }
  if (Promise._onHandle) {//同樣不屬于本篇考慮范疇
    Promise._onHandle(self);
  }
  if (self._state === 0) {//promise狀態(tài)為pending時(shí)
    if (self._deferredState === 0) {//沒有deferreds時(shí)
      self._deferredState = 1;//deferreds變?yōu)閱蝹€(gè)
      self._deferreds = deferred;傳入deferreds入列
      return;
    }
    if (self._deferredState === 1) {
      self._deferredState = 2;//deferreds變?yōu)閿?shù)組
      self._deferreds = [self._deferreds, deferred];//傳入deferred進(jìn)入數(shù)組
      return;
    }
    self._deferreds.push(deferred);//已經(jīng)是數(shù)組了就直接push增加
    return;
  }
  handleResolved(self, deferred);//新東西,在state!==0時(shí)傳入promise和defered
}

可以看到其實(shí)這個(gè)函數(shù)在對_deferreds進(jìn)行添加,進(jìn)行著_deferreds的修改和寫入,與finale()所做的事情恰恰相反,但是詳細(xì)的處理卻還是在handleResolved()函數(shù)里面.

handleResolved()
function handleResolved(self, deferred) {
  asap(function() {//注意!asap是一個(gè)引入的模塊,意思就是as soon as possible,就是盡快執(zhí)行的意思,我們不需要考慮它做了什么.
    // promise狀態(tài)是fulfilled情況下cb為deferred中的Fulfilled函數(shù),不是的話則為onRejected函數(shù)...
    var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
    if (cb === null) {//如果不存在對應(yīng)狀態(tài)的函數(shù)
      if (self._state === 1) {//當(dāng)前promise對象是否為fulfilled狀態(tài)
        resolve(deferred.promise, self._value);//傳入deferred中保存的promise和當(dāng)前promise的值進(jìn)行resolve
      } else {
        reject(deferred.promise, self._value);//與上類似,進(jìn)行reject
      }
      return;
    }
    var ret = tryCallOne(cb, self._value);//存在則嘗試執(zhí)行對應(yīng)函數(shù),返回執(zhí)行結(jié)果(與兩個(gè)參數(shù)的tryCall不同,這里返回了函數(shù)運(yùn)行結(jié)果)
    if (ret === IS_ERROR) {//有錯(cuò)誤,reject
      reject(deferred.promise, LAST_ERROR);
    } else {//沒錯(cuò)誤,對deferred.promise用函數(shù)返回值進(jìn)行resolve
      resolve(deferred.promise, ret);
    }
  });
}

這里我們看到了deferred是一個(gè)保存了promise對象,onFulfilled函數(shù),onRejected函數(shù)的對象,相當(dāng)于一個(gè)保存現(xiàn)場.其實(shí)這里就是我們即將在源碼core.js解析(下)寫到的handler對象了.但是這里我們暫且先不深究,知道就好了.
handleResolved()毫無疑問就是在進(jìn)行著promise的終值傳遞處理,對舊promise對象的狀態(tài)修改,并調(diào)用resolvereject獲取到值/拒因向下一個(gè)Promise傳遞.對這里的詳細(xì)實(shí)例分析我們放到(下)來講.

構(gòu)造一個(gè)Promise時(shí)發(fā)生了啥?

從簡單看起,我們構(gòu)造一個(gè)Promise對象的時(shí)候經(jīng)過了哪些函數(shù)
先理一下思路.

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

這里面首先是先構(gòu)造了Promise對象,我們稱為A,在構(gòu)造階段執(zhí)行了如下代碼.
檢查略....

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

檢查傳入?yún)?shù)不為空....

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

然后我們跳到了doResolve()函數(shù)處,傳入為fn,promise

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

我們又根據(jù)我們的輸入跳轉(zhuǎn)到了resolve(promise,value)啦,這里理一下我們的函數(shù),promise就是A,value其實(shí)就是我們傳入的"ok".
所以執(zhí)行的是promise內(nèi)部中的resolve(promise,"ok")
經(jīng)過一系列判斷(詳細(xì)可以看規(guī)范),我們的"ok"過五關(guān)斬六將直接執(zhí)行到這一步.

self._state = 1;//A狀態(tài)變?yōu)閒ulfilled
self._value = newValue;//AA終值變?yōu)?ok"

然后我們finale(self)啦,繼續(xù)跳到finale()函數(shù),傳入了A.

//在過程中我們的_deferredState始終為0呀,看了一下
A._deferredState = 0;
//已經(jīng)沒有什么好做的了...

我們的構(gòu)造已經(jīng)結(jié)束了!這就是我們new 一個(gè)Promise時(shí)的過程,跟著思路走,其實(shí)加上reject也是同樣的路線而已.

(上)結(jié)語

(下)的話我打算重點(diǎn)寫剩余部分的then函數(shù)流程,并盡量用簡單的語言來描述,希望自己能進(jìn)一步理解promise,發(fā)現(xiàn)有錯(cuò)漏能及時(shí)修訂.

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/80393.html

相關(guān)文章

  • Promise學(xué)習(xí)筆記(四):源碼core.js解析(下)

    摘要:源碼閱讀階段緊接上一篇這次我們開始我們最常用到的部分的源碼解析傳入?yún)?shù)為兩個(gè)函數(shù)和判斷調(diào)用者是否為對象跳轉(zhuǎn)到了一個(gè)叫做的函數(shù)里面新建一個(gè)對象傳入函數(shù)傳入給和一個(gè)新的對象返回新的對象在這里我們先看看在調(diào)用者不是對象時(shí)到底做了什么比想象的要簡單 源碼閱讀階段 緊接上一篇,這次我們開始Promise我們最常用到的then部分的源碼解析. then() //傳入?yún)?shù)為兩個(gè)函數(shù),onFulfil...

    VincentFF 評論0 收藏0
  • JS筆記

    摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。異步編程入門的全稱是前端經(jīng)典面試題從輸入到頁面加載發(fā)生了什么這是一篇開發(fā)的科普類文章,涉及到優(yōu)化等多個(gè)方面。 TypeScript 入門教程 從 JavaScript 程序員的角度總結(jié)思考,循序漸進(jìn)的理解 TypeScript。 網(wǎng)絡(luò)基礎(chǔ)知識之 HTTP 協(xié)議 詳細(xì)介紹 HTT...

    rottengeek 評論0 收藏0
  • 前端最實(shí)用書簽(持續(xù)更新)

    摘要:前言一直混跡社區(qū)突然發(fā)現(xiàn)自己收藏了不少好文但是管理起來有點(diǎn)混亂所以將前端主流技術(shù)做了一個(gè)書簽整理不求最多最全但求最實(shí)用。 前言 一直混跡社區(qū),突然發(fā)現(xiàn)自己收藏了不少好文但是管理起來有點(diǎn)混亂; 所以將前端主流技術(shù)做了一個(gè)書簽整理,不求最多最全,但求最實(shí)用。 書簽源碼 書簽導(dǎo)入瀏覽器效果截圖showImg(https://segmentfault.com/img/bVbg41b?w=107...

    sshe 評論0 收藏0
  • Promise學(xué)習(xí)筆記(二):規(guī)范

    摘要:下一篇大概就是源碼方面的學(xué)習(xí)筆記了龜速學(xué)習(xí)中這一次我是去看了下規(guī)范照例傳送門圖靈社區(qū)規(guī)范首先吧個(gè)人總結(jié)下該用的詞解決結(jié)婚拒絕婉拒終值值傳家寶拒因好人卡等等異常車禍理下概念我們的的就像是一場姻緣對吧解決呢就是結(jié)婚成功啦傳家寶也如愿的傳給下一代 下一篇大概就是源碼方面的學(xué)習(xí)筆記了...龜速學(xué)習(xí)中... 這一次我是去看了下Promises/A+規(guī)范照例傳送門:圖靈社區(qū)Promises/A+規(guī)...

    _Suqin 評論0 收藏0
  • 前端知識歸納

    摘要:繼承性子標(biāo)簽會繼承父標(biāo)簽樣式優(yōu)先級行內(nèi)樣式選擇器類選擇器標(biāo)簽選擇器通配符繼承機(jī)制創(chuàng)建了的元素中,在垂直方向上的會發(fā)生重疊。 技能考察: 一、關(guān)于Html 1、html語義化標(biāo)簽的理解; 結(jié)構(gòu)化的理解; 能否寫出簡潔的html結(jié)構(gòu); SEO優(yōu)化 a、理解:根據(jù)內(nèi)容的結(jié)構(gòu)化(內(nèi)容語義化),選擇合適的標(biāo)簽(代碼語義化)便于開發(fā)者閱讀和寫出更優(yōu)雅的代碼的同時(shí) 讓瀏覽器的爬蟲和...

    sixleaves 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<