摘要:源碼閱讀階段緊接上一篇這次我們開始我們最常用到的部分的源碼解析傳入參數為兩個函數和判斷調用者是否為對象跳轉到了一個叫做的函數里面新建一個對象傳入函數傳入給和一個新的對象返回新的對象在這里我們先看看在調用者不是對象時到底做了什么比想象的要簡單
源碼閱讀階段
緊接上一篇,這次我們開始Promise我們最常用到的then部分的源碼解析.
then()//傳入參數為兩個函數,onFulfilled和onRejected Promise.prototype.then = function(onFulfilled, onRejected) { //判斷調用者是否為Promise對象 if (this.constructor !== Promise) { //跳轉到了一個叫做safeThen的函數里面 return safeThen(this, onFulfilled, onRejected); } //新建一個promise對象,傳入function(){}. var res = new Promise(noop); //handle函數,傳入給promise,和一個新的Handler對象. handle(this, new Handler(onFulfilled, onRejected, res)); //返回新的promise對象res return res; };
在這里我們先看看在調用者不是Promise對象時,safeThen到底做了什么.
safeThenfunction 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)); }); }
比想象的要簡單點,它直接根據傳入的非Promise對象return了一個新的Promise對象.并且和then函數一樣調用了handle()函數.也就是說該函數相當于new了個Promise再調用then函數一樣.
handle函數在上篇我們已經對其進行過閱讀,現在可以繼續看一下這一次情況有什么不同,方便閱讀只放部分代碼.
function handle(self, deferred) {傳入一個promise對象和handler對象 //略檢測代碼 if (self._state === 0) {//promise對象狀態為pending if (self._deferredState === 0) {//defereds為null時,將handler對象放入defereds self._deferredState = 1; self._deferreds = deferred; return; } if (self._deferredState === 1) {//defereds為單個時,將defereds轉為數組,將handler對象放入defereds數組 self._deferredState = 2; self._deferreds = [self._deferreds, deferred]; return; } //defereds為數組時,直接push添加 self._deferreds.push(deferred); return; } //promise對象狀態不為pending時,傳入promise和handler對象,進行處理 handleResolved(self, deferred); }
很好,接下來就是handleResolved的內部處理了,還記得上篇我們說的deferred是一個保存了promise對象,onFulfilled函數,onRejected函數的對象,這句話么,這里我們可以得出handler對象就是我們上篇所認為的deferred.而defereds就是保存它們的地方.
handler對象function Handler(onFulfilled, onRejected, promise){ this.onFulfilled = typeof onFulfilled === "function" ? onFulfilled : null; this.onRejected = typeof onRejected === "function" ? onRejected : null; this.promise = promise; }
這里就很簡單易懂了,handler就是這么一個東西,里面有promise對象,有onFulfilled函數,有onRejected函數.
中途整理可以看到then函數其實就是將我們傳入了onFulfilled函數和onRejected函數和新建的一個promise對象,把三者封裝到一個handler里面.然后在handle函數里面把handler放進調用then函數的promise對象的_deffereds里面.
值得注意的是
//promise對象狀態不為pending時,傳入promise和handler對象,進行處理 handleResolved(self, deferred);
這一段代碼表示了當調用的promise部位pending狀態的時候,將會對我們promise對象的_deferreds進行處理.
結合我們上一章看到的finale()中對promise對象的_deferred的循環handle處理,我們可以構建起整整一條關于調用的鏈,光說,還是不如直接說案例啦.
var B = new Promise(function(resolve,reject){ console.log("construct pending"); resolve("ok"); }); B .then(function(value){ console.log(value); throw "ex"; },function(reason){ console.log("first"); }) .then(function(value){ console.log("second success"); console.log(value); },function(reason){ console.log("second error"); console.log(reason); }) .catch(function(reason){ console.log("catch error"); console.log(reason); });
例子如上,我們逐步拆分
new Promise()var B = new Promise(function(resolve,reject){ console.log("construct pending"); resolve("ok"); });
這里我們傳入了一個函數,并console.log出了"construct pending"的字樣,然后進行了resolve,參考上一篇的流程,答案顯而易見,B的數據如下
A._deferredState = 0; A._state = 1; A._value = "ok"; A._deferreds = null;
然后我們就調用了then函數,我們跟著思路繼續走.
B.then().then(function(value){ console.log(value); throw "ex"; },function(reason){ console.log("first"); })
這是第一個then,我們跳到源碼看一下內部做了啥,為了方便記憶,我們把傳入的onFulfilled函數記為T1,onRejected函數記為T2,B也就稱為B~
B.then(T1,T2)
我們就對其進行探討吧,首先在源碼中先判斷調用者是否為Promise對象,B.constructor!==Promise,而這明顯是Promise對象,所以不需要進行safeThen()(雖然說safeThen也只是進行一次轉換,這里不深究),然后我們就新建了一個res變量保存new Promise(function(){})
執行 handle(this,new Handler(onFulfilled, onRejected, res));
然后返回res
傳入this為B,傳入的handler綁定了新建并應該返回的promise對象res,還有T1,T2函數.
顯現檢測B是否為pending狀態,結果并不是!
中間對defereds處理直接跳過.直接進行handleResolved(B,handler)
檢查B._state為1也就是fulfilled狀態,返回handler.onFulfilled給cb變量.
跳過cb===null的判定
執行tryCallOne(cb,B._value) 等同于
tryCallOne(function(value){ console.log(value); throw "ex"; },"ok");
所以,可以發現console.log除了"ok"字串,然后在tryCallOne中拋出了異常.根據上篇中tryCallOne源碼
//內部捕獲錯誤,單個參數函數 function tryCallOne(fn, a) { try { return fn(a); } catch (ex) { LAST_ERROR = ex; return IS_ERROR; } }
我們發現其中拋出了錯誤被成功捕獲了并返回了標識錯誤IS_ERROR.LAST_ERROR = "ok"
所以變量ret賦值為IS_ERROR
調用reject(res,"ex")
傳入參數為res,"ex"
res._state = 2; 也就是讓res狀態變為rejected
res._value = "ex"; 讓res拒因變為"ex"
接下來的if不成立,我們不需理會.
然后調用了finale(res)
傳入參數為res
由于res._deferredState = 0,所以finale不進行任何操作,至此結束handle(this,new Handler(onFulfilled, onRejected, res))的操作,執行返回res的操作.
更改處為:
res._state = 2; res._value = "ex";
所以傳遞給下一個then的promise對象為res,狀態為rejected拒因為"ex"
第二個then()調用它的promise對象為上訴返回的res,我們改稱為resultA
resultA.then(function(value){ console.log("second success"); console.log(value); },function(reason){ console.log("second error"); console.log(reason); })
跟著上面的思路走,我們清楚的知道主要處理時在handle(this,new Handler(onFulfilled, onRejected, res))的操作.
而resultA顯而易見,狀態也不為pending,直接執行handleResolved(resultA,handler)
handleResolved中像上次一樣,執行了tryCallOne(),但是這次要注意,并沒有錯誤被拋出,所以var ret獲取到的是函數執行后的返回值,為空.
function(reason){ console.log("second error"); console.log(reason); } //并沒有返回任何東西
值console.log出了"second error"和"ex"(resultA._value).
那么接下來呢,沒錯,ret為空了...也就是沒有錯誤呀
然后我們就進入了resolv(handler.promise,ret)
傳入的ret為空值,根據規范,這直接就跳到了
self._state = 1;//promise狀態為fulfilled self._value = ret;//值傳遞 finale(self);//finale了
至于finale我們也不用理會,等于直接結束了handle()的執行,然后返回的promise對象我們成為resultB,然后數據如下:
resultB._state = 1;//為fulfilled resultB._value = null;//為空值
傳遞給下一個then的為fulfilled狀態,終值為null的promise對象resultB
catch()根據之前的博文,我們提到過catch(fn)等同于then(undefined,fn)
主要的原因在于handleResolve中
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; }
那么fulfilled狀態下調用的函數自然與handler構造中變為null的onFulfilled有關了.調用了resolve(deferred.promise, self._value);
傳入新建的promise和null為終值.
新建的promise我們稱為resultC
resultC._state = 1; resultC._value = null;
所以在catch這段處理中
.catch(function(reason){ console.log("catch error"); console.log(reason); })
并不會出現任何console,因為該函數并沒有被執行.
catch執行后返回promise對象為resultC,大家可以用.then(function(value){console.log(value)})驗證下,console出來會是undefined
持續進行修訂吧,有時間再補上函數跳轉處理圖,還有Promise.race和Promise.all函數大概要等到比較久之后才會去寫啦~明天開始回歸繼續做些小玩意
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/80387.html
摘要:源碼閱讀階段先理解根本吧想快點理解的話可以直接跳到下個標題這部分根據理解將持續修改空函數用于判斷傳入構造器的函數是否為空函數如果為空函數構造一個對象并初始化狀態為終值回調狀態和隊列記錄內部最后的一次錯誤空對象標識表示發生了錯誤暴露模塊接口為 源碼閱讀階段 先理解Promise根本吧,想快點理解的話可以直接跳到下個標題.這部分根據理解將持續修改. Promise(fn) function...
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。異步編程入門的全稱是前端經典面試題從輸入到頁面加載發生了什么這是一篇開發的科普類文章,涉及到優化等多個方面。 TypeScript 入門教程 從 JavaScript 程序員的角度總結思考,循序漸進的理解 TypeScript。 網絡基礎知識之 HTTP 協議 詳細介紹 HTT...
摘要:回調函數成功回調處理器失敗回調處理器用戶發送一個向百度服務器獲取數據的異步請求無阻塞高并發的的誕生更加嚴重的依賴異步操作才能完成無阻賽高并發的特性。 Promise Promise 是什么? 詞語本意: 發音:[?pr?m?s] 詞性:名詞, 翻譯:許諾,允諾。 MDN解釋 Promise 對象用于一個異步操作。 一個Promise表示一個現在,將來或永不可能可用的值。 按照書寫方...
摘要:下一篇大概就是源碼方面的學習筆記了龜速學習中這一次我是去看了下規范照例傳送門圖靈社區規范首先吧個人總結下該用的詞解決結婚拒絕婉拒終值值傳家寶拒因好人卡等等異常車禍理下概念我們的的就像是一場姻緣對吧解決呢就是結婚成功啦傳家寶也如愿的傳給下一代 下一篇大概就是源碼方面的學習筆記了...龜速學習中... 這一次我是去看了下Promises/A+規范照例傳送門:圖靈社區Promises/A+規...
閱讀 767·2023-04-25 15:13
閱讀 1388·2021-11-22 12:03
閱讀 816·2021-11-19 09:40
閱讀 1898·2021-11-17 09:38
閱讀 1702·2021-11-08 13:18
閱讀 649·2021-09-02 15:15
閱讀 1760·2019-08-30 15:54
閱讀 2623·2019-08-30 11:12