2018-6-27 seo達(dá)人
如果您想訂閱本博客內(nèi)容,每天自動發(fā)到您的郵箱中, 請點這里
Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案–回調(diào)函數(shù)和事件--更合理和更強大。它由社區(qū)最早提出和實現(xiàn),ES6將其寫進(jìn)了語言標(biāo)準(zhǔn),統(tǒng)一了語法,原生提供了Promise
所謂Promise ,簡單說就是一個容器,里面保存著某個未來才回結(jié)束的事件(通常是一個異步操作)的結(jié)果。從語法上說,Promise是一個對象,從它可以獲取異步操作的消息。
三種狀態(tài):
狀態(tài)改變:
這兩種情況只要發(fā)生,狀態(tài)就凝固了,不會再變了,這時就稱為resolved(已定型
基本用法
ES6規(guī)定,Promise對象是一個構(gòu)造函數(shù),用來生成Promise實例
Promise的源碼分析:
曾幾何時,我們的代碼是這樣的,為了拿到回調(diào)的結(jié)果,不得不
終于,我們的
首先我們要知道自己手寫一個
我們先聲明一個類,叫做
那么接下來我會分析上面代碼的作用,原理
then方法是
這里主要做了將構(gòu)造器中resolve和reject的結(jié)果傳入
之前我們只是處理了同步情況下的Promise,簡而言之所有操作都沒有異步的成分在內(nèi)。那么如果是異步該怎么辦?
最早處理異步的方法就是callback,就相當(dāng)于我讓你幫我掃地,我會在給你發(fā)起任務(wù)時給你一個手機(jī),之后我做自己的事情去,不用等你,等你掃完地就會打手機(jī)給我,誒,我就知道了地掃完了。這個手機(jī)就是callback,回調(diào)函數(shù)。
首先我們需要改一下構(gòu)造器里的代碼,分別添加兩個回調(diào)函數(shù)的數(shù)組,分別對應(yīng)成功回調(diào)和失敗回調(diào)。他們的作用是當(dāng)成功執(zhí)行resolve或reject時,執(zhí)行callback。
然后是then需要多加一個狀態(tài)判斷,當(dāng)Promise中是異步操作時,需要在我們之前定義的回調(diào)函數(shù)數(shù)組中添加一個回調(diào)函數(shù)。
ok!大功告成,異步已經(jīng)解決了
這也是
一下子多了很多方法,不用怕,我會一一解釋
那就讓我們來看看這個
它的作用是用來將onFufilled的返回值進(jìn)行判斷取值處理,把最后獲得的值放入最外面那層的
我們現(xiàn)在已經(jīng)基本完成了Promise的then方法,那么現(xiàn)在我們需要看看他的其他方法。
相信大家都知道catch這個方法是用來捕獲Promise中的reject的值,也就是相當(dāng)于then方法中的onRejected回調(diào)函數(shù),那么問題就解決了。我們來看代碼。
該方法是掛在Promise原型上的方法。當(dāng)我們調(diào)用catch傳callback的時候,就相當(dāng)于是調(diào)用了then方法。
大家一定都看到過
這兩個方法是直接可以通過class調(diào)用的,原理就是返回一個內(nèi)部是resolve或reject的Promise對象。
all方法可以說是Promise中很常用的方法了,它的作用就是將一個數(shù)組的Promise對象放在其中,當(dāng)全部resolve的時候就會執(zhí)行then方法,當(dāng)有一個reject的時候就會執(zhí)行catch,并且他們的結(jié)果也是按著數(shù)組中的順序來排放的,那么我們來實現(xiàn)一下。
其原理就是將參數(shù)中的數(shù)組取出遍歷,每當(dāng)執(zhí)行成功都會執(zhí)行
race方法雖然不常用,但是在Promise方法中也是一個能用得上的方法,它的作用是將一個
原理大家應(yīng)該看懂了,很簡單,就是遍歷數(shù)組執(zhí)行Promise,如果有一個
語法糖這三個字大家一定很熟悉,作為一個很Swag的前端工程師,對async/await這對兄弟肯定很熟悉,沒錯他們就是generator的語法糖。而我們這里要講的語法糖是Promise的。
什么作用呢?看下面代碼你就知道了
沒錯,我們可以方便的去調(diào)用他語法糖defer中的
Promise 的含義
Promise 對象的狀態(tài)不受外界影響
Promise對象的狀態(tài)改變,只有兩種可能:
resolve
函數(shù)的作用是,將Promise對象的狀態(tài)從“未完成”變?yōu)椤俺晒Α保磸?nbsp;pending
變?yōu)?nbsp;resolved
),在異步操作成功時調(diào)用,并將異步操作的結(jié)果,作為參數(shù)傳遞出去;
reject
函數(shù)的作用是,將Promise對象的狀態(tài)從“未完成”變?yōu)椤笆 保磸?nbsp;pending
變?yōu)?nbsp;rejected
),在異步操作失敗時調(diào)用,并將異步操作報出的錯誤,作為參數(shù)傳遞出去。
1.回調(diào)地獄
callback hell
,這種環(huán)環(huán)相扣的代碼可以說是相當(dāng)惡心了
蓋世英雄
出現(xiàn)了,他身披金甲圣衣、駕著七彩祥云。好吧打岔兒了,沒錯他就是我們的Promise
,那讓我們來看看用了Promise
之后,上面的代碼會變成什么樣吧
2.重點開始,小眼睛都看過來
2.1 Promise/A+
Promise
,應(yīng)該怎么去寫,誰來告訴我們怎么寫,需要遵循什么樣的規(guī)則。當(dāng)然這些你都不用擔(dān)心,其實業(yè)界都是通過一個規(guī)則指標(biāo)來生產(chǎn)Promise
的。讓我們來看看是什么東西。傳送門?Promise/A+
2.2 constructor
Promise
,里面是構(gòu)造函數(shù)。如果es6還有問題的可以去阮大大的博客上學(xué)習(xí)一下(傳送門?es6)
executor:
這是實例Promise
對象時在構(gòu)造器中傳入的參數(shù),一般是一個function(resolve,reject){}
status:``Promise
的狀態(tài),一開始是默認(rèn)的pendding狀態(tài),每當(dāng)調(diào)用道resolve和reject方法時,就會改變其值,在后面的then方法中會用到
value:
resolve回調(diào)成功后,調(diào)用resolve方法里面的參數(shù)值
reason:
reject回調(diào)成功后,調(diào)用reject方法里面的參數(shù)值
resolve:
聲明resolve方法在構(gòu)造器內(nèi),通過傳入的executor方法傳入其中,用以給使用者回調(diào)
reject:
聲明reject方法在構(gòu)造器內(nèi),通過傳入的executor方法傳入其中,用以給使用者回調(diào)
2.3 then
Promise
中最為重要的方法,他的用法大家都應(yīng)該已經(jīng)知道,就是將Promise
中的resolve或者reject的結(jié)果拿到,那么我們就能知道這里的then方法需要兩個參數(shù),成功回調(diào)和失敗回調(diào),上代碼!
onFufilled
和onRejected
中,注意這兩個是使用者傳入的參數(shù),是個方法。所以你以為這么簡單就完了?要想更Swag
的應(yīng)對各種場景,我們必須得再完善。繼續(xù)往下走!
3.異步的Promise
3.1 callback?。。。?
3.2 resolvePromise
Promise
中的重頭戲,我來介紹一下,我們在用Promise的時候可能會發(fā)現(xiàn),當(dāng)then函數(shù)中return了一個值,我們可以繼續(xù)then下去,不過是什么值,都能在下一個then中獲取,還有,當(dāng)我們不在then中放入?yún)?shù),例:promise.then().then()
,那么其后面的then依舊可以得到之前then返回的值,可能你現(xiàn)在想很迷惑。讓我來解開你心中的憂愁,follow me。
Promise
?:首先我們要注意的一點是,then有返回值,then了之后還能在then,那就說明之前的then返回的必然是個Promise
。
setTimeout
?:因為Promise本身是一個異步方法,屬于微任務(wù)一列,必須得在執(zhí)行棧執(zhí)行完了在去取他的值,所以所有的返回值都得包一層異步setTimeout。
resolvePromise
是什么?:這其實是官方Promise/A+的需求。因為你的then可以返回任何職,當(dāng)然包括Promise
對象,而如果是Promise
對象,我們就需要將他拆解,直到它不是一個Promise
對象,取其中的值。
resolvePromise
到底長啥樣。
Promise
的resolve函數(shù)中。
promise2
(then函數(shù)返回的Promise對象),x
(onFufilled函數(shù)的返回值),resolve、reject
(最外層的Promise上的resolve和reject)。
promise2
和x
?:首先在Promise/A+中寫了需要判斷這兩者如果相等,需要拋出異常,我就來解釋一下為什么,如果這兩者相等,我們可以看下下面的例子,第一次p2是p1.then出來的結(jié)果是個Promise
對象,這個Promise
對象在被創(chuàng)建的時候調(diào)用了resolvePromise(promise2,x,resolve,reject)函數(shù),又因為x等于其本身,是個Promise
,就需要then方法遞歸它,直到他不是Promise
對象,但是x(p2)的結(jié)果還在等待,他卻想執(zhí)行自己的then方法,就會導(dǎo)致等待。
resolvePromise
函數(shù)已經(jīng)resolve或者reject了,那就不需要在執(zhí)行下面的resolce或者reject。
resolvePromise
函數(shù)?:相信細(xì)心的人已經(jīng)發(fā)現(xiàn)了,我這里使用了遞歸調(diào)用法,首先這是Promise/A+中要求的,其次是業(yè)務(wù)場景的需求,當(dāng)我們碰到那種Promise的resolve里的Promise的resolve里又包了一個Promise的話,就需要遞歸取值,直到x不是Promise對象。
4.完善Promise
4.1 catch
4.2 resolve/reject
Promise.resolve()、Promise.reject()
這兩種用法,它們的作用其實就是返回一個Promise對象,我們來實現(xiàn)一下。
4.3 all
processData
方法,processData
方法就是用來記錄每個Promise的值和它對應(yīng)的下標(biāo),當(dāng)執(zhí)行的次數(shù)等于數(shù)組長度時就會執(zhí)行resolve,把arr的值給then。這里會有一個坑,如果你是通過arr數(shù)組的長度來判斷他是否應(yīng)該resolve的話就會出錯,為什么呢?因為js數(shù)組的特性,導(dǎo)致如果先出來的是1位置上的值進(jìn)arr,那么0位置上也會多一個空的值,所以不合理。
4.4 race
Promise
數(shù)組放入race中,哪個先執(zhí)行完,race就直接執(zhí)行完,并從then中取值。我們來實現(xiàn)一下吧。
Promise
執(zhí)行成功就resolve。
Promise語法糖 deferred
Promise
對象。那么它還有沒有另外的方法呢?答案是有的。我們需要在全局上安裝promises-aplus-tests插件npm i promises-aplus-tests -g
,再輸入promises-aplus-tests [js文件名] 即可驗證你的Promise的規(guī)范。
藍(lán)藍(lán)設(shè)計( m.yvirxh.cn )是一家專注而深入的界面設(shè)計公司,為期望卓越的國內(nèi)外企業(yè)提供卓越的UI界面設(shè)計、BS界面設(shè)計 、 cs界面設(shè)計 、 ipad界面設(shè)計 、 包裝設(shè)計 、 圖標(biāo)定制 、 用戶體驗 、交互設(shè)計、 網(wǎng)站建設(shè) 、平面設(shè)計服務(wù)
藍(lán)藍(lán)設(shè)計的小編 http://m.yvirxh.cn