promise解決回撥地獄;啥?前端還有“地獄?”

前端小鐵人發表於2019-10-17

前言:

當我過去初學JavaScript的時候,覺得令人最讓人難以琢磨的就是函式,在某些方面函式物件的應用,確實給我帶了很多方便。 JavaScript語言的執行環境是“單執行緒”的,所以試想一下,如果在JavaScript中沒有非同步操作,我們根本就不能使用它了。其中回撥函式,就是早期用它來解決非同步操作問題的。

【有關非同步操作,我將會在之後的文章中,與大家共談,關於Generator】

回撥函式的用法之廣,比如在某段程式碼中插入回撥函式,意味著將之前的打包好的“程式碼塊”在某處再執行一次,上文中,也闡述了回撥函式能解決非同步程式設計的問題。 但是大家有沒有想過,當回撥函式巢狀過多導致回撥函式累積,我們的程式碼維護起來是不是就是極其的複雜,多層回撥函式的巢狀使我們的程式碼就偏離了“高內聚,低耦合”的設計理念,牽一髮而動全身。

所以我們將多層回撥函式的巢狀,我們稱之為:回撥地獄。(跟地獄這個詞扯上關係,都不是啥好事)。

當回撥函式層層巢狀過多時,我們將不再運用回撥函式解決非同步操作問題,我們使用Promise。

在ES6語言標準規定中,Promise是一個物件,代表著一個非同步操作,它可以獲取非同步操作的訊息,進而改變Promise自身的狀態。Promise這個物件有三種狀態:1.等待pending2.已失敗reject3.已成功fulfill。

有了Promise物件,我們就可以將非同步操作以同步的方式表達出來。(這給Promise物件厲害的,但是它也有弊端,我將在文末與大家說明。)

##基本用法: ```//ES6中規定,promise物件是一個建構函式,用來生成Promise例項。

var promise = new Promise(function(resolve,reject) {
    //我們剛建立Promise物件時,P是pending狀態。Promise物件用一個函式作為引數,並且這個
    函式有兩個引數resolve與reject,值得注意的是這兩個引數也是兩個函式。(“敲黑板了,別被我繞
    暈了鐵子們”),我們呼叫這兩個函式,就會將Promise的狀態切換到相對應的狀態,呼叫resolve,
    會切換到成功狀態(並將非同步操作的結果作為引數傳遞給外面);呼叫reject是失敗的狀態。
    
})

Promise例項生成之後,我們可以通過then方法分別指定Resolved狀態和Rejected狀態的回撥函式。
【Promise只是給了回撥函式一個平臺,我們將非同步操作以同步方式表達出來】
promise.then(function(data) {
    //當promise切換到fulfill狀態時,會呼叫該函式
    console.log('當狀態為fulfill我才會被呼叫',data)
},function(error) {
//【在此我們要注意:第二個回撥函式是可選的】
    //當promise切換到reject狀態時,會呼叫該函式
    console.log('當狀態為reject我才會被呼叫',error)
})
//【then方法可以接受兩個回撥函式作為引數,這兩個回撥函式的引數都是都是promise物件傳出的值】。

//promise物件新建之後就會立即執行,then方法指定的回撥函式將在當前指令碼所有的同步任務執行完成之後才
會執行。

最後我們來談一談Promise物件的缺點。
first:
    我們一旦建立了Promise物件,它是無法取消的,並且它會立即執行(箭在弦上)
second:
    我們必須要將Promise與回撥函式結合使用,意思是說,如果我們不通過then方法設定回撥函式,
    Promise物件的結果將不會反應到外部。
    
    
【以上,就是我向大家介紹的有關Promise的初級概念,我將在下一篇文章中,
向大家介紹Promise物件的其他方法比如catch,all等方法】
複製程式碼

總結:我在這裡向大家打個比方,在沒有Promise物件之前,我們層層巢狀的回撥函式就像是手動扔手榴彈 ,我們一通猛扔,但是並不知道各個手榴彈的爆之後炸資訊;當我們引用Promise物件之後, 對我們來說不是扔手榴彈了,而是像發射導彈一樣,精準定位,精確打擊,並且我們通 導彈發射裝置的雷達系統(Promise),能得到每次發射的結果,來決定我們下次是否還 要繼續發射。

相關文章