摘要:說(shuō)白了,就是給聲明的添加一個(gè)包含空的對(duì)象,再由函數(shù)返回這個(gè)空。如此構(gòu)成一個(gè)層層包裹的鏈。四首先本質(zhì)是一個(gè)遞歸函數(shù),結(jié)束條件是,即終止到未掛載對(duì)象的子為止。可以看到這個(gè)函數(shù)的作用就是根據(jù)屬性逐個(gè)觸發(fā)鏈中的或函數(shù)。
背景
Promise是一種非常實(shí)用的異步編程方案,本文對(duì)于Promise源碼的分析可以增進(jìn)讀者對(duì)于Promise原理的理解,以后不再害怕異步編程,不用擔(dān)心callback hell,對(duì)于Promise的運(yùn)用也將更加游刃有余;另外對(duì)于源碼的閱讀也是對(duì)自己代碼能力提升的一種有效手段,本文會(huì)從實(shí)踐到原理將Promise進(jìn)行一次徹底的解剖,希望會(huì)對(duì)讀者有所助益。
文章組織安排本文會(huì)分四個(gè)部分進(jìn)行介紹
第一部分:Promise鏈?zhǔn)接|發(fā)原理,及resolve(), reject(),then()的實(shí)現(xiàn)
第二部分:promise的在實(shí)踐中的幾個(gè)特性及其實(shí)現(xiàn)
第三部分:promise的幾個(gè)主要的類方法和對(duì)象方法的實(shí)現(xiàn)
第四部分:promise錯(cuò)誤處理機(jī)制
var promiseObj = new Promise(function(resolve, reject){ setTimeout(function(){ resolve("to then1"); }, 1000); }); promiseObj.then(function(val){ console.log(val); return "to then2"; }).then(function(val){ console.log(val); });
以上是一段簡(jiǎn)單的promise處理異步操作的代碼,初始化中有一個(gè)包含setTimeout異步操作的函數(shù),在兩個(gè)then中定義了兩個(gè)異步操作后的執(zhí)行函數(shù);promise的作用是實(shí)現(xiàn)在異步操作完成之后去觸發(fā)then中聲明的函數(shù),以取代之前不斷定義callback的方式,將異步操作通過(guò)同步的寫法實(shí)現(xiàn),使得程序書寫符合開放封閉原則;整個(gè)的實(shí)現(xiàn)過(guò)程分這么幾步:
promise實(shí)例化Promise.prototype.then()創(chuàng)建promise鏈
resolve遞歸觸發(fā)promise鏈
以下是接下來(lái)將用到的幾個(gè)工具函數(shù),其作用已經(jīng)在注釋中說(shuō)明
//聲明一個(gè)空函數(shù),用于初始化一個(gè)沒(méi)有執(zhí)行邏輯的promise var noop = function(){}; var IS_ERROR = {}; var LAST_ERROR = null; //將a作為fn的參數(shù)進(jìn)行執(zhí)行 function tryCallOne(fn, a) { try{ return fn(a); }catch(e){ LAST_ERROR = e; return IS_ERROR; } } //將a, b作為fn的參數(shù)執(zhí)行 function tryCallTwo(fn, a, b) { try{ return fn(a, b); }catch(e){ LAST_ERROR = e; return IS_ERROR; } }
以下是promise的構(gòu)造函數(shù)
function Promise(fn) {
/* * _deferredState:用于指示promise是否添加過(guò)deferred * _deferred:延遲對(duì)象原型是Handler * _state:promise執(zhí)行狀態(tài)pengind:0,fulfilled:1 * _value:defered函數(shù)執(zhí)行參數(shù)*/ this._deferredState = 0; this._deferred = null; this._state = 0; this._value = null; doResolved(this, fn); }
其中_deferred對(duì)象包含一個(gè)promise對(duì)象和then中定義的執(zhí)行成功(resolved)和執(zhí)行失敗(rejected)時(shí)的延遲執(zhí)行函數(shù),相當(dāng)于是promise的一個(gè)鏈條,其構(gòu)造函數(shù)是如下所示的Handler
//我是deferred對(duì)象的構(gòu)造函數(shù)
function Handler(onFulfilled, onRejected, promise) {
this.onFulfilled = typeof onFulfilled === "function"? onFulfilled: null; this.onRejected = typeof onRejected === "function"? onRejected: null; this.promise = promise; }
其他幾個(gè)屬性已經(jīng)在注釋中說(shuō)明,實(shí)例化的第一步就是要執(zhí)行doResolved函數(shù)了,promise在實(shí)例化時(shí)會(huì)傳入一個(gè)包含異步操作的函數(shù)暫時(shí)稱之為fn,在這個(gè)函數(shù)中包含兩個(gè)參數(shù),這兩個(gè)參數(shù)就是執(zhí)行成功或失敗時(shí)用來(lái)調(diào)用then中函數(shù)的函數(shù)(有點(diǎn)繞口哈哈);而doResolved的作用就是為這個(gè)fn傳入這兩個(gè)參數(shù)而生的。
function doResolved(self, fn) {
tryCallTwo(fn, function(val){ resolve(self, val); },function(val){ reject(self, val); }); }
以上就是promise實(shí)例化的全過(guò)程了
二、promise.prototype.then的原理then的作用實(shí)際是為了創(chuàng)建一個(gè)promise鏈,先將then中聲明的函數(shù)包在promise1中,再返回一個(gè)沒(méi)有執(zhí)行邏輯的promise2,然后將后一個(gè)then中聲明的函數(shù)包在promise2中,如此構(gòu)造一個(gè)promise鏈
Promise.prototype.then = function(onFulfilled, onRejected){
var res = new Promise(noop);//一個(gè)沒(méi)有執(zhí)行邏輯的空promise handle(this, new Handler(onFulfilled, onRejected, res));//包一個(gè)promise在當(dāng)前promise中 return res; };
Handler在之前已經(jīng)提到過(guò),接下來(lái)看看handle這個(gè)函數(shù)都干了啥
//將原始的promise對(duì)象構(gòu)造為一個(gè)包含子promise的鏈?zhǔn)絧romise
function handle(self, deferred) { if(self._deferredState === 0){ self._deferredState = 1; self._deferred = deferred; return; } }
handle函數(shù)傳入兩個(gè)參數(shù),一個(gè)是promise本身,另一個(gè)是包含一個(gè)沒(méi)有處理邏輯的空promise的deferred對(duì)象,整個(gè)的處理邏輯就是將deferred對(duì)象賦給promise的deferred屬性,然后再將_deferredState切換為1,指示promise已添加過(guò)deferred對(duì)象。說(shuō)白了,handle就是給聲明的promise添加一個(gè)包含空promise的deferred對(duì)象,再由then函數(shù)返回這個(gè)空promise。如此構(gòu)成一個(gè)層層包裹的promise鏈。
三、resolve&rejectfunction reject(self, newValue){
self._state = 2; self._value = newValue; if(self._deferredState === 1){handleResolved(self, self._deferred);}
}
function resolve(self, newValue){
self._state = 1; self._value = newValue; if(self._deferredState === 1){handleResolved(self, self._deferred);}
}
resolve和reject兩個(gè)函數(shù)記錄下外部傳來(lái)的參數(shù),并將promise的狀態(tài)記錄在_state屬性中,供接下來(lái)的handleResolved函數(shù)觸發(fā)promise鏈用。
function handleResolved(self, deferred) {
asap(function(){ var cb = self.state === 1 ? deferred.onFulfilled : deferred.onRejected; var ret = tryCallOne(cb, self._value); resolve(deferred.promise, ret); return; })
}
首先handleResolve本質(zhì)是一個(gè)遞歸函數(shù),結(jié)束條件是self._deferredState !== 1,即終止到未掛載deferred對(duì)象的子promise為止。另外執(zhí)行deferred對(duì)象內(nèi)部函數(shù)的代碼包裹在asap模塊中,asap模塊相當(dāng)于一個(gè)插隊(duì)作用,包含在其中的任務(wù)會(huì)在當(dāng)前線程的所有排隊(duì)任務(wù)隊(duì)列全部執(zhí)行完后執(zhí)行,但又會(huì)在新線程之前執(zhí)行即setTimeout中的任務(wù)之前。之前在知乎上看到關(guān)于該問(wèn)題的討論,真相就是這個(gè)asap了。可以看到這個(gè)handleResolved函數(shù)的作用就是根據(jù)_state屬性逐個(gè)觸發(fā)promise鏈中的onFulFilled或onRejected函數(shù)。
以上是在對(duì)promise源碼 閱讀后,針對(duì)promise的幾個(gè)功能對(duì)整體簡(jiǎn)化之后的代碼及總結(jié),之后會(huì)根據(jù)promise的幾個(gè)特性完善各個(gè)函數(shù),還你一個(gè)完整的promise。源碼請(qǐng)戳這里。
六、來(lái)一道promise測(cè)試題function timeout() { var promiseObj = new Promise(function(resolve, reject){ console.log("1"); resolve(); }); return promiseObj; } timeout().then(function(){ setTimeout(function(){console.log("2")}, 500); }).then(function(){ console.log("3") }); console.log("4");
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/94532.html
摘要:只有動(dòng)手,你才能真的理解作者的構(gòu)思的巧妙只有動(dòng)手,你才能真正掌握一門技術(shù)持續(xù)更新中項(xiàng)目地址求求求源碼系列跟一起學(xué)如何寫函數(shù)庫(kù)中高級(jí)前端面試手寫代碼無(wú)敵秘籍如何用不到行代碼寫一款屬于自己的類庫(kù)原理講解實(shí)現(xiàn)一個(gè)對(duì)象遵循規(guī)范實(shí)戰(zhàn)手摸手,帶你用擼 Do it yourself!!! 只有動(dòng)手,你才能真的理解作者的構(gòu)思的巧妙 只有動(dòng)手,你才能真正掌握一門技術(shù) 持續(xù)更新中…… 項(xiàng)目地址 https...
摘要:前言整理中一些相似的關(guān)鍵字方法概念。于是我們修改上面的函數(shù)來(lái)驗(yàn)證它們的區(qū)別小明擼代碼擼代碼小紅小黑小剛小紅小黑擼代碼小李小謝小剛小李小謝擼代碼那么與有什么區(qū)別呢與和不同的是,綁定后不會(huì)立即執(zhí)行。通常用來(lái)處理一些并發(fā)的異步操作。 前言 整理 javascript 中一些相似的關(guān)鍵字、方法、概念。 1. var、function、let、const 命令的區(qū)別 使用var聲明的變量,其作...
摘要:本篇文章將會(huì)嘗試用簡(jiǎn)單易懂的語(yǔ)言描述的原理,并且用手?jǐn)]一個(gè)簡(jiǎn)單的。一個(gè)后可以通過(guò)方法,指定和時(shí)的回調(diào)函數(shù)。實(shí)現(xiàn)實(shí)現(xiàn)狀態(tài)機(jī)因?yàn)槭且粋€(gè)構(gòu)造函數(shù),使用的寫法,首先想到的就是有顯式聲明的。 說(shuō)到Promise,都知道它是比回調(diào)函數(shù)更優(yōu)的一種異步編程解決方案,它可以使得異步操作邏輯變得更加清晰,是解決地獄回調(diào)的一種嘗試。本篇文章將會(huì)嘗試用簡(jiǎn)單易懂的語(yǔ)言描述Promise的原理,并且用es6手?jǐn)]一...
摘要:我們將登錄按鈕上綁上事件,點(diǎn)擊登錄之后向服務(wù)端提交賬號(hào)和密碼進(jìn)行驗(yàn)證。所以前端和后端權(quán)限的劃分是不太一致。側(cè)邊欄最后一個(gè)涉及到權(quán)限的地方就是側(cè)邊欄,不過(guò)在前 完整項(xiàng)目地址:vue-element-admin 系列文章: 手摸手,帶你用vue擼后臺(tái) 系列一(基礎(chǔ)篇) 手摸手,帶你用vue擼后臺(tái) 系列二(登錄權(quán)限篇) 手摸手,帶你用vue擼后臺(tái) 系列三 (實(shí)戰(zhàn)篇) 手摸手,帶你用vu...
摘要:年前無(wú)心工作,上班刷知乎發(fā)現(xiàn)一篇分享爬蟲的文章。另外攜帶的數(shù)據(jù)是用來(lái)告訴服務(wù)器當(dāng)前請(qǐng)求是從哪個(gè)頁(yè)面請(qǐng)求過(guò)來(lái)的。 年前無(wú)心工作,上班刷知乎發(fā)現(xiàn)一篇分享python爬蟲的文章。 感覺(jué)他爬取的網(wǎng)站里的妹子都好好看哦,超喜歡這里的,里面?zhèn)€個(gè)都是美女。 無(wú)小意丶:自我發(fā)掘爬蟲實(shí)戰(zhàn)1:宅男女神網(wǎng)妹子圖片批量抓取,分類保存到本地和MongoDB數(shù)據(jù)庫(kù) 無(wú)奈python雖然入門過(guò)但太久沒(méi)用早已荒廢,最...
閱讀 1985·2021-11-22 14:45
閱讀 2593·2021-10-12 10:11
閱讀 768·2021-09-22 10:02
閱讀 1198·2019-08-30 15:55
閱讀 1142·2019-08-30 15:54
閱讀 3247·2019-08-30 15:54
閱讀 1181·2019-08-29 17:16
閱讀 3080·2019-08-28 17:55