開發(fā)者的javascript造詣取決于對(duì)【動(dòng)態(tài)】和【異步】這兩個(gè)詞的理解水平。
網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)建站!專注于網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、成都微信小程序、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了柞水免費(fèi)建站歡迎大家使用!
Promise
技術(shù)是【javascript
異步編程】這個(gè)話題中非常重要的,它一度讓我感到熟悉又陌生,我熟悉其所有的API
并能夠在編程中相對(duì)熟練地運(yùn)用,卻對(duì)其中原理和軟件設(shè)計(jì)思想感到陌生,即便我讀了很多源碼分析和教程也一度很難理解為什么Promise
這樣一個(gè)普通的類能夠?qū)崿F(xiàn)異步,也曾嘗試著去按照Promise/A+規(guī)范來編寫Promise
,但很快便陷入了一種更大的混亂之中。直到我接觸到一些軟件設(shè)計(jì)思想以及軟件工程方面的知識(shí)后,從代碼之外的角度來理解一些細(xì)節(jié)的必要性時(shí),那些陌生才開始一點(diǎn)點(diǎn)消失。
如果你覺得有些新東西很那理解,有很大的原因是因?yàn)槟愫驮O(shè)計(jì)者所擁有的基礎(chǔ)知識(shí)儲(chǔ)備不是一個(gè)水平的,導(dǎo)致你無法理解設(shè)計(jì)者寫出某段代碼時(shí)所基于的指導(dǎo)思想,當(dāng)你無法理解某些看起來很復(fù)雜的東西時(shí),筆者的建議是先了解它希望解決的問題,這個(gè)問題或許是具體的業(yè)務(wù)邏輯需求,或許是抽象的軟件設(shè)計(jì)層面的,然后嘗試自己想辦法去解決它,請(qǐng)永遠(yuǎn)記得別人是開發(fā)者,你也是,你要做的是面向需求,而不僅僅是跟著別人走。即時(shí)最終你沒能開發(fā)出這個(gè)模塊而去學(xué)習(xí)源碼時(shí),你也會(huì)發(fā)現(xiàn)面對(duì)需求而進(jìn)行的主動(dòng)思考對(duì)此帶來的幫助。
Promise
的本質(zhì),是一個(gè)分布式的狀態(tài)機(jī)。而PromiseAPI
的本質(zhì),就是一個(gè)發(fā)布訂閱模型。
Promise
解決了什么問題?
這是一個(gè)最基本的問題,Promise
是一個(gè)有關(guān)可靠性和狀態(tài)管理的編程范式,它通常被認(rèn)為從代碼層面將javascript
中著名的回調(diào)地獄改變成扁平化的寫法,并為指定的業(yè)務(wù)邏輯打上狀態(tài)標(biāo)記,讓開發(fā)者可以更容易地控制代碼執(zhí)行的流程。但事實(shí)上Promise
的設(shè)計(jì)初衷并不是為了實(shí)現(xiàn)異步,而且很多開發(fā)者并沒有意識(shí)到,回調(diào)并不意味著異步!??!(你傳入另一個(gè)函數(shù)的回調(diào)函數(shù)有可能被異步執(zhí)行,也有可能被同步執(zhí)行)。想更好地理解Promise
,就必須把【異步】這個(gè)標(biāo)簽從中剝離,而圍繞【狀態(tài)管理】,【可靠性】這些關(guān)鍵詞進(jìn)行展開。
Promise
只是一個(gè)類,為什么就能夠?qū)崿F(xiàn)異步?
Promise
本身的確只是一個(gè)普通的類,而且在不依賴ES6
的環(huán)境中,開發(fā)者甚至可以手動(dòng)實(shí)現(xiàn)這樣一個(gè)類,在沒有研究Promise
的代碼之前,筆者一直主觀地認(rèn)為其內(nèi)部是通過類似于事件監(jiān)聽的機(jī)制來實(shí)現(xiàn)異步的,否則程序本身怎么會(huì)知道發(fā)出的http
請(qǐng)求什么時(shí)候返回結(jié)果。
這個(gè)問題是在筆者學(xué)習(xí)完EventLoop
和Generator
函數(shù)的相關(guān)知識(shí)后才理解的,其實(shí)Promise
本身并沒有實(shí)現(xiàn)異步,javascript
語言中的異步都是通過事件循環(huán)的機(jī)制(《javascript基礎(chǔ)修煉(5)——Event Loop(node.js)》)來實(shí)現(xiàn)的,簡(jiǎn)單地說就是說異步事件的響應(yīng)是會(huì)被事件循環(huán)不斷去主動(dòng)檢測(cè)的,當(dāng)異步動(dòng)作滿足了再次被執(zhí)行的條件時(shí)(比如http
請(qǐng)求返回了結(jié)果,或者在另一個(gè)線程開啟的大運(yùn)算量的邏輯執(zhí)行完畢后返回了消息),就會(huì)被加入調(diào)用棧來執(zhí)行,Promise
和Generator
只是配合事件循環(huán)來進(jìn)行狀態(tài)管理和流程控制,它們本身和事件循環(huán)的機(jī)制是解耦的。
Promise
作為構(gòu)造函數(shù)調(diào)用而生成實(shí)例時(shí)到底發(fā)生了什么事情?
這里所指的是下面這樣的代碼:
promise = new Promise(function(resolve, reject){
//....
});
面試中經(jīng)常會(huì)問到有關(guān)Promise
執(zhí)行次序的問題,很多非常熟悉Promise
用法的讀者也并沒有意識(shí)到,實(shí)際上傳入的匿名函數(shù)是會(huì)同步執(zhí)行的。Promise
所做的事情,是為當(dāng)前這個(gè)不知道何時(shí)能完成的動(dòng)作打上一些狀態(tài)的標(biāo)記,并傳入兩個(gè)用于回收控制權(quán)的方法作為參數(shù)來啟動(dòng)執(zhí)行這個(gè)匿名函數(shù),通過then
方法指定的后續(xù)執(zhí)行邏輯會(huì)先緩存起來(這里的描述并不嚴(yán)謹(jǐn)),當(dāng)這個(gè)異步動(dòng)作完成后調(diào)用resolve
或者reject
方法后,再繼續(xù)執(zhí)行事先被緩存起來的流程。
Promise/A+標(biāo)準(zhǔn)看起來很復(fù)雜,該如何去實(shí)現(xiàn)?
Promise/A+規(guī)范的確很復(fù)雜,我也不建議你直接就通過這樣的方式來了解Promise
的實(shí)現(xiàn)細(xì)節(jié),【規(guī)范】意味著嚴(yán)謹(jǐn)性,也表示其中有很多容錯(cuò)的機(jī)制,這會(huì)極大地妨礙你對(duì)Promise
核心邏輯的理解,Promise
代碼大的復(fù)雜性,在于它對(duì)于鏈?zhǔn)秸{(diào)用的支持(如果不需要支持鏈?zhǔn)秸{(diào)用,你會(huì)發(fā)現(xiàn)自己幾乎不需要思考就可以分分鐘擼一個(gè)Promise
庫出來)。筆者的建議是先想辦法去解決主要問題,再對(duì)照Promise/A+規(guī)范去檢視自己的代碼。
Promise為什么要實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用?
鏈?zhǔn)秸{(diào)用的實(shí)現(xiàn),實(shí)現(xiàn)了Promise
的多步驟流程控制功能,對(duì)一個(gè)多于兩個(gè)步驟的流程中,即使沒有實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用,Promise
實(shí)際上依然可以工作,但當(dāng)你真的那樣做時(shí),你會(huì)發(fā)現(xiàn)它又變成了一個(gè)新的回調(diào)地獄。
Promise的可靠性是指什么?
Promise
的可靠性指它的狀態(tài)只能被改變一次,之后就不能再修改,且唯一修改它的方法是調(diào)用promise
實(shí)例中的內(nèi)部resolve( )
或reject( )
方法,它們是定義在Promise
內(nèi)部的,從外部無法訪問到,只能通過Promise
內(nèi)部提供的機(jī)制來觸發(fā)判定方法(new Promise(executor)
生成實(shí)例時(shí),當(dāng)還行到executor時(shí),Promise會(huì)將內(nèi)部的resolve
和reject
方法作為實(shí)參傳入executor,從而暴露修改自身狀態(tài)的能力),相比之下,普通對(duì)象的屬性或者thenable
對(duì)象(指擁有then
方法的非Promise實(shí)例對(duì)象)的屬性都是可以被直接修改的,所以promise
的狀態(tài)和結(jié)果被認(rèn)為是更可靠的。
假設(shè)有一個(gè)異步的動(dòng)作A,還有一個(gè)希望在A完成以后執(zhí)行的動(dòng)作B,和一個(gè)在B完成以后去執(zhí)行的動(dòng)作C,我們來看一下Promise
是如何實(shí)現(xiàn)流程控制。
A動(dòng)作開始之前,我們把它丟進(jìn)Promise
構(gòu)造函數(shù),Promise
給了A一個(gè)控制器(上面有resolve和reject兩個(gè)按鈕)和一個(gè)帶有兩個(gè)抽屜的儲(chǔ)物柜(onFulfilledCallbacks和onRejectedCallbacks),接著給A交代:我已經(jīng)登記好信息了,你去執(zhí)行吧,等你執(zhí)行完以后,如果你認(rèn)為執(zhí)行成功了,就按一下控制器的resolve按鈕,如果認(rèn)為執(zhí)行失敗了就按一下reject按鈕,但是你要小心,這個(gè)控制器只能用一次,按完它會(huì)自動(dòng)發(fā)送消息,儲(chǔ)物柜上有接收器,如果收到resolve
信號(hào),onFulfilledCallbacks這個(gè)抽屜就會(huì)打開,如果收到reject
信號(hào),onRejectedCallbacks這個(gè)抽屜就會(huì)打開,之后另一個(gè)柜子就會(huì)鎖死,我每隔一段時(shí)間會(huì)來查看一下你的狀態(tài)(注意這里是在事件循環(huán)中主動(dòng)輪詢來查看promise
實(shí)例是否執(zhí)行結(jié)束的),如果我看到你的儲(chǔ)物柜有一個(gè)抽屜打開了的話的話,就會(huì)把里面的東西拿出來依次執(zhí)行接下來的事情。在這之前,如果有人想關(guān)注你的執(zhí)行情況的話,我會(huì)讓它留下兩張字條,分別寫下不同的抽屜打開的時(shí)需要做的事情,因?yàn)樽罱K只有一個(gè)抽屜可以打開,他必須得寫兩張字條,除非他只關(guān)注某個(gè)抽屜的動(dòng)向,然后使用你這個(gè)儲(chǔ)物柜的then
方法就可以把字條塞到對(duì)應(yīng)的柜子里,之后等抽屜打開時(shí),我只需要根據(jù)字條上的信息打電話給他就行了。A覺得這樣是比較穩(wěn)妥的,于是拿著promise給它的控制器去執(zhí)行了。
代碼繼續(xù)執(zhí)行,這時(shí)候出現(xiàn)了一個(gè)B,B說我得先看看A的執(zhí)行結(jié)果,再?zèng)Q定做什么,執(zhí)行器說你也別在這干等著了,A在我們這里存放了一個(gè)智能儲(chǔ)物柜,它回頭會(huì)把結(jié)果遠(yuǎn)程發(fā)送回來,你把你的聯(lián)系方式寫在這兩張字條上,然后通過A的儲(chǔ)物柜的then
方法放進(jìn)去吧,聯(lián)系方式也可以寫成不一樣的,到時(shí)候A返回結(jié)果的話,對(duì)應(yīng)的抽屜就會(huì)打開,我按照你寫的聯(lián)系方式發(fā)消息給你就行了。B想了想也是,于是就寫下了兩個(gè)不同的號(hào)碼放進(jìn)了A儲(chǔ)物柜對(duì)應(yīng)的抽屜里,接著就回家睡覺去了。
代碼繼續(xù)執(zhí)行,這時(shí)候又出現(xiàn)了一個(gè)C,C說我想等B返回結(jié)果以后再執(zhí)行,這時(shí)候執(zhí)行器犯難了,B還沒出發(fā)呢,我也沒有給它分配回調(diào)儲(chǔ)物柜,所以沒辦法用同樣的方式對(duì)待C,執(zhí)行器只能對(duì)C說,我們這規(guī)定如果沒有對(duì)應(yīng)標(biāo)記的儲(chǔ)物柜的話,暫時(shí)不提供服務(wù),這樣吧,你先把你的聯(lián)系方式寫好交給我,等回頭如果B出發(fā)的話,我會(huì)給它分派儲(chǔ)物柜,到時(shí)候把你的需求放在對(duì)應(yīng)的抽屜里,等B返回對(duì)應(yīng)結(jié)果以后我再通知你,C覺得也行,于是就照做了。但是C走后,執(zhí)行器就想了,要是后面再來DEF都要跟在不同的人后面去執(zhí)行,那這些事情我都得先保管著,這也太累了,而且容易搞亂,不能這么搞啊。
上一會(huì)講到在現(xiàn)有機(jī)制下缺乏多步驟流程管理的機(jī)制,當(dāng)異步任務(wù)A執(zhí)行且沒有返回結(jié)果時(shí),后續(xù)所有的動(dòng)作都被暫存在了執(zhí)行器手里,只能隨著時(shí)間推移,當(dāng)標(biāo)志性事件發(fā)生時(shí)再逐步去分發(fā)事件。為了能夠?qū)崿F(xiàn)多步驟的流程管理,執(zhí)行器想出了一個(gè)方法,為每一個(gè)來注冊(cè)后續(xù)業(yè)務(wù)邏輯的人都提供一個(gè)智能儲(chǔ)物柜,這樣在辦理登記時(shí)就可以直接將后續(xù)的方法分發(fā)到對(duì)應(yīng)的抽屜里,常見的問題就解決了。
如果沒有鏈?zhǔn)秸{(diào)用,第三節(jié)中的多步驟的偽代碼可能是如下的樣子:
//為了聚焦核心邏輯,下面的偽代碼省略了onReject的回調(diào)
promiseA = new Promise(function(resolve, reject){
//A帶著控制器開始執(zhí)行
A(resolve,reject);
});
promiseA.then(function(resA){
//A執(zhí)行結(jié)束以后,開始判斷B到底是否要執(zhí)行
promiseB = new Promise(function(resolveB, rejectB){
//如果B需要執(zhí)行,則分配兩個(gè)儲(chǔ)物柜,并派發(fā)狀態(tài)控制器,B帶著A返回的數(shù)據(jù)resA開始執(zhí)行
B(resA,resolveB,rejectB);
});
promiseB.then(function(resB){
//B執(zhí)行結(jié)束以后,開始判斷C到底是否要執(zhí)行
promiseC = new Promise(function(resolveC, rejectC){
//如果C需要執(zhí)行,則分配兩個(gè)儲(chǔ)物柜,并派發(fā)狀態(tài)控制器,C帶著B返回的數(shù)據(jù)resB開始執(zhí)行
C(resB, resolveC, rejectC);
});
//...如果有D的話
})
});
在邏輯流程中僅僅有3個(gè)步驟的時(shí)候,回調(diào)地獄的苗頭就已經(jīng)顯露無疑了。Promise
被設(shè)計(jì)用來解決回調(diào)嵌套過深的問題,如果只能按上面的方法來使用的話顯然是不能滿足需求的。如果可以支持鏈?zhǔn)秸{(diào)用,那么上面代碼的編寫方式就變成了:
//為了聚焦核心邏輯,下面的偽代碼省略了onReject的回調(diào)
promiseA = new Promise(function(resolve, reject){
//A帶著控制器開始執(zhí)行
A(resolve,reject);
});
promiseA.then(function(resA){
//在使用then方法向A的儲(chǔ)物柜里存放事件的同時(shí),也生成了自己的儲(chǔ)物柜
return new Promise(function(resolveB, rejectB){
B(resA, resolveB, rejectB);
});
}).then(function(resB){
return new Promise(function(resolveC, rejectC){
C(resB, resolveC, rejectC);
});
}).then(function(resC){
//如果有D動(dòng)作,則繼續(xù)
})
很明顯,當(dāng)流程步驟增多時(shí),支持鏈?zhǔn)秸{(diào)用的方法具有更好的擴(kuò)展性。下一節(jié)講一下Promise
最關(guān)鍵的鏈?zhǔn)秸{(diào)用環(huán)節(jié)的實(shí)現(xiàn)。
如果需要then
方法支持鏈?zhǔn)秸{(diào)用,則Promise.prototype.then
這個(gè)原型方法就需要返回一個(gè)新的promise
。事實(shí)上即使在最初的時(shí)間節(jié)點(diǎn)上來看,后續(xù)注冊(cè)的任務(wù)也符合在未來某個(gè)不確定的時(shí)間會(huì)返回結(jié)果的特點(diǎn),只是多了一些前置條件的限制。返回新的promise
實(shí)例是非常容易做到的,但從代碼編寫的邏輯來理解,這里的promise
到底是什么意思呢?先看一下基本實(shí)現(xiàn)的偽代碼:
//為簡(jiǎn)化核心邏輯,此處只處理Promise狀態(tài)為PENDING的情況
//同時(shí)也省略了容錯(cuò)相關(guān)的代碼
Promise.prototype.then = function(onFulfilled, onRejected){
let that = this;
return new Promise(function(resolve, reject){
//對(duì)onFulfilled方法的包裝和歸類
that.onFulfilledCallbacks.push((value) => {
let x = onFulfilled(value);
someCheckMethod(resolve, x, ...args);
});
//對(duì)onRejected方法的包裝和歸類
that.onRejectedCallbacks.push((reason) => {
let x = onRejected(reason);
someCheckMethod(reject, x, ...args);
});
});
};
可以看到在支持鏈?zhǔn)秸{(diào)用的機(jī)制下,最終被添加至待執(zhí)行隊(duì)列中的函數(shù)并不是通過then
方法添加進(jìn)去的函數(shù),而是通過Promise
包裝為其增加了狀態(tài)信息,并且將這個(gè)狀態(tài)改變的控制權(quán)交到了onFulfilled
函數(shù)中,onFulfilled
函數(shù)的返回結(jié)果,會(huì)作為參數(shù)傳入后續(xù)的判定函數(shù),進(jìn)而影響在執(zhí)行resolve
的執(zhí)行邏輯,這樣就將新promise
控制權(quán)暴露在了最外層。
所以,then方法中返回的promise實(shí)例,標(biāo)記的就是添加進(jìn)去的
onFulfilled
和onRejected
方法的執(zhí)行狀態(tài)。這里的關(guān)鍵點(diǎn)在于,onFulfilled
函數(shù)執(zhí)行并返回結(jié)果后,才會(huì)啟動(dòng)對(duì)于這個(gè)promise的決議。
在新的鏈?zhǔn)秸{(diào)用的支持下,上面的故事流程就發(fā)生了變化。當(dāng)B前來登記事件時(shí),執(zhí)行器說我們這現(xiàn)在推出了一種委托服務(wù),你想知道那個(gè)儲(chǔ)物柜的最新動(dòng)態(tài),就把你的電話寫在字條上放在對(duì)應(yīng)的抽屜里,之后當(dāng)這個(gè)抽屜打開后,我們就會(huì)把它返回的信息發(fā)送到你留在字條上的號(hào)碼上,我們會(huì)給你提供一個(gè)智能儲(chǔ)物柜(帶有this._onFulfillCallbacks
抽屜和this._onRejectedCallbacks
抽屜)和一個(gè)控制器,這樣別人也可以關(guān)注你的動(dòng)態(tài),但你的控制器暫時(shí)不能用,我們將某個(gè)消息發(fā)送到你留的手機(jī)號(hào)碼上時(shí),才會(huì)同步激活你的控制器功能,但它也只能作用一次。
再來考慮一種特殊的場(chǎng)景,就是當(dāng)A動(dòng)作調(diào)用resolve(value )
方法來改變狀態(tài)機(jī)的狀態(tài)時(shí),傳入的參數(shù)仍然是一個(gè)PENDING
狀態(tài)的promise
,這相當(dāng)于A說自己已經(jīng)完成了,但是此時(shí)卻無法得到執(zhí)行結(jié)果,也就不可能將結(jié)果作為參數(shù)來啟動(dòng)對(duì)應(yīng)的apromise._onFulfilledCallbacks
隊(duì)列或者apromise_onRejectedCallbacks
隊(duì)列,此時(shí)只能先等著這個(gè)promise
改變狀態(tài),然后才能執(zhí)行對(duì)A動(dòng)作的決議。也就是說A的決議動(dòng)作要延遲到這個(gè)新的promise
被決議以后。用偽代碼來表示這種情況的處理策略就是如下的樣子:
//內(nèi)部方法
let that = this;//這里的this指向了promise實(shí)例
function resolve(result){
if(result instanceof Promise){
return result.then(resolve, reject);
}
//執(zhí)行相應(yīng)的緩存隊(duì)列里的函數(shù)
setTimeout(() => {
if (that.status === PENDING) {
that.status = FULFILLED;
that.value = result;
that.onFulfilledCallbacks.forEach(cb => cb(that.result));
}
});
}
當(dāng)前promise
實(shí)例的決議通過result.then(resolve,reject)被推遲到result返回結(jié)果之后,而真正執(zhí)行時(shí)所需要操作的對(duì)象和屬性,已經(jīng)通過let that = this與實(shí)例進(jìn)行了綁定 。
很多開發(fā)者在這里會(huì)覺得非?;靵y,很可能是沒有意識(shí)到每一個(gè)promise
實(shí)例都會(huì)生成內(nèi)部方法resolve( )
和reject( )
,即時(shí)當(dāng)Promise
類實(shí)例化的過程結(jié)束后,它們依然會(huì)被保持在自己的閉包作用域中,在執(zhí)行棧中涉及到多個(gè)處于PENDING
狀態(tài)的promise
時(shí),它們的內(nèi)部方法都是存活的。如果還是覺得抽象,可以利用Chrome的調(diào)試工具,將下面的代碼逐步執(zhí)行,并觀察右側(cè)調(diào)用棧,就可以看到當(dāng)傳入決議函數(shù)的是另一個(gè)promise
時(shí),外層的決議函數(shù)都會(huì)以閉包的形式繼續(xù)存在。
let promise1 = new Promise(function(resolve, reject){
setTimeout(function fn1(){
let subpromise = new Promise(function (resolvesub,rejectsub) {
setTimeout(function fn2() {
resolvesub('value from fn2');
},2000);
});
resolve(subpromise);
},2000);
});
promise1.then(function fn3(res) {
console.log(res);
});
【Promise/A+規(guī)范】:https://github.com/promises-aplus/promises-spec
理清了上面各種情況的基本策略后,我們已經(jīng)具備了構(gòu)建一個(gè)相對(duì)完備的Promise
模塊的能力。我強(qiáng)烈建議你按照Promise/A+規(guī)范來親自動(dòng)手實(shí)現(xiàn)一下這個(gè)模塊,你會(huì)發(fā)現(xiàn)在實(shí)現(xiàn)的過程中仍然有大量的代碼層面的問題需要解決,但你一定會(huì)受益于此。網(wǎng)上有非常多的文章講述如何根據(jù)Promise/A+標(biāo)準(zhǔn)來實(shí)現(xiàn)這個(gè)庫,可是在筆者看來這并不是什么值得炫耀的事情,就好像對(duì)照著攻略在打游戲一樣。
作為工程師,你既要能夠一行一行寫出這樣一個(gè)模塊,更要關(guān)注規(guī)范為什么要那樣規(guī)定。
【Promise/A+測(cè)試套件】: https://github.com/promises-aplus/promises-tests
如果你對(duì)照規(guī)范的要求寫出了這個(gè)模塊,可以利用官方提供的測(cè)試套件(包含800多個(gè)測(cè)試用例來測(cè)試規(guī)范中規(guī)定的各個(gè)細(xì)節(jié))來測(cè)試自己編寫的模塊并完善它。javascript語言中都是通過鴨式辯型來檢測(cè)接口的,無論你是怎樣實(shí)現(xiàn)規(guī)范的各個(gè)要求,只要最終通過測(cè)試套件的要求即可。如果你依舊覺得心里沒譜,也可以參考別人的博文來學(xué)習(xí)Promise
的細(xì)節(jié),例如這篇《Promise詳解與實(shí)現(xiàn)》就給了筆者很大幫助。
當(dāng)越過了語言層面的難點(diǎn)后,推薦你閱讀《深入理解Promise五部曲》這個(gè)系列的文章。大多數(shù)開發(fā)者對(duì)于Promise
的理解和應(yīng)用都是用來解決回調(diào)地獄問題的,而這個(gè)系列的文章會(huì)讓你從另一個(gè)角度重新認(rèn)識(shí)Promise,不得不說文章中用發(fā)布訂閱模式來類比解釋Promise
的實(shí)現(xiàn)機(jī)制對(duì)于筆者理解Promise提供了巨大的幫助,同時(shí)它也能夠引發(fā)一些通過學(xué)習(xí)promise/A+規(guī)范很難意識(shí)到的關(guān)于精髓和本質(zhì)的思考。
創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國云服務(wù)器,動(dòng)態(tài)BGP最優(yōu)骨干路由自動(dòng)選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機(jī)房獨(dú)有T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確進(jìn)行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動(dòng)現(xiàn)已開啟,新人活動(dòng)云服務(wù)器買多久送多久。