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