ES6——Promise

  Promise是ES6中新增的一個對象,主要是爲了解決異步操做的問題而新增的一個方法數組

定義

  Promise用來表示一個異步的狀態(成功/失敗)以及返回的值異步

  也就是說,Promise裏放着的是將來要作的事情函數

  關於執行的順序,Promise對象在建立後會當即執行,then在當前全部同步腳本執行完後執行對象

  例如以下案例blog

  

  輸出的順序爲:Promise、Hello、resolved圖片

  解析以下:字符串

  1.Promise對象建立後當即執行,所以輸出了Promise回調函數

  2.then對象中的語句要到當前腳本全部同步任務執行完後再執行,因此resolved暫時不輸出,先輸出Hello同步

  3.最後,當前腳本內全部的同步任務執行完,執行then裏的語句,resolved輸出it

  下面一個案例也是關於異步同步問題的

  

  輸出結果爲:123465

  過程以下:

  1.一、四、6不用過多說明,同步任務,按照代碼的前後依次執行便可

  2.Promise實例在建立的時候就馬上執行,因此2和3也依次輸出

  3.因爲then方法是在全部同步任務執行完後執行,因此5最後輸出

 

狀態

  Promise裏共有三種狀態:進行中pending)、成功fulfilled)、失敗rejected

  其中狀態的改變稱爲決議,而狀態只能夠從pendding變動到fulfilled/rejected不可逆也不可在fulfilled/rejected裏互換

  也就是說在Promise裏,只有pending--->fulfilled或者pending--->rejected,沒有第三種

 

基本方法

  使用時,須要先構建一個Promise對象的實例

  這個實例接收兩個參數,一個是回調成功時執行的函數(習慣性命名resolve),另外一個是回調失敗時執行的函數(習慣性命名reject)

  而若是想在某次回調後繼續鏈式回調,則返回構建Promise對象實例的函數,這樣一來,就是返回了一個Promise實例,繼續等待傳入回調成功和失敗時的執行函數

  固然,還能夠向resolve和reject裏傳入參數,回調的時候能夠輸出,但只能夠傳入一個參數,多餘的參數不被接收

 

  使用的時候,利用Promise實例中的then方法,接收兩個參數,第一個爲回調成功時執行的函數(resolve),第二個是回調失敗時執行的函數(reject)

  而若是想鏈式調用,則直接在執行完resolve/reject後返回Promise實例,這樣一來,下次繼續等待傳入兩個回調函數

  

  實際上也能夠不返回Promise實例,這樣一來then裏的函數會同以前全部Promise實例後的then一同執行

  例如這裏的1和2都是1s後輸出的,而345則是12輸出後的1s後輸出(由於返回的Promise實例是要1s後回調的),能夠理解成輸出1後返回了一個「啥也沒幹」的Promise

  then裏若是想返回Promise實例,return必定要寫在then的執行函數後面

  

 

錯誤處理

catch

  Promise裏能夠傳入reject函數來對錯誤進行處理,若是沒有,須要用catch語句來接收錯誤並處理

  

  該段代碼的執行順序以下:

  1.由於給test輸入了true,因此執行的是resolve函數,這裏resolve函數傳入的參數ok,而then裏的data只是個形參,執行的最後返回Promise對象並傳入false

  2.第二個鏈式調用的then裏,只傳入了resolve函數,沒有reject函數,但因爲這裏Promise對象裏是false,應該執行reject函數,因此沒有輸出

  3.第三個鏈式調用爲catch,捕獲了第二個then裏沒有捕獲的錯誤,裏面傳入的參數能夠理解爲reject函數e形參,最後輸出404

  

  可是,若是錯誤被reject處理了,那後面的catch就不起做用

  

   實際上,能夠在最後的catch裏再次返回一個錯誤,讓後面的catch解決,但會出現一個問題,有可能最後一個catch拋出了錯誤,可是沒有解決。這一點上,ES6暫時沒有解決方法

finally

  Promise實例中還有個finally方法,能夠放在鏈式調用的最後,其中的代碼不管如何都會執行

  注意若是finally執行時還有錯誤未處理,則會報錯,說明Promise裏的錯誤未處理

  

  

 

優勢

  Promise提升了代碼的可讀性可維護性

  Promise的使用最大的好處是,解決了以前多層嵌套回調的問題

  例如,咱們須要建立一個回調函數,用來在1s後執行咱們傳入的一個函數,若是說只是回調一次,直接調用這個回調函數,傳入1s後執行的函數,便可

  但若是是要依賴上一次回調的結果,再去執行一次回調函數,那就須要嵌套兩層了,不過也還行

  可若是是嵌套到五六層呢?嵌套了這麼多層之後,若是須要更改其中兩次的執行順序呢?彷佛就沒辦法操做了,堪稱回調地獄(以下圖)

  

  可若是使用Promise對象來寫這一段代碼,就變成了下面的樣子

  

  相比於以前的層層套的寫法,這裏採用了鏈式調用的方法,若是哪裏須要修改內容或順序,能夠直接修改then裏的內容,或者調整then的順序,解決了多層嵌套的問題

  

Promise對象的方法

all

  用來接收一個數組,裏面每一項是一個Promise實例,最後包裝成一個新的Promise實例

  注意這裏傳入的必須是數組(可迭代),不然會報錯(not iterable)

  分三種狀況:

  1.全部的Promise決議爲成功,.all的決議也爲成功,把全部Promise實例的resolve中傳入的參數組成一個數組返回,其順序符合Promise實例的順序

  

  2.有一個Promise決議爲失敗,.all決議爲失敗,把這個決議失敗的reject傳入的參數做爲錯誤返回

  有多個Promise決議爲失敗時,輸出的參數只有第一個reject傳入的參數

  

  3.傳入空數組,決議爲成功,輸出then中給resolve傳入的參數

  

race

  相似於all,race裏傳入的參數也是Promise實例,不過返回時,按照第一個返回的決議決定race的決議狀況,執行then裏的resolve或reject

  若是返回的速度同樣,則按照傳入時的第一個Promise實例的決議來決定執行resolve/reject

  

  但若是傳入的爲空,則什麼都不執行,會一直「掛」在那裏

  

resolve&reject

  這裏的resolve和reject不是Promise實例或者then裏傳入的參數,而是Promise實例的方法,用來生成被決議爲成功/失敗的Promise實例

  也就是說,不管傳入的是什麼,resolve/reject返回的都是一個Promise實例

resolve

  resolve方法中能夠傳入:

  1.普通值(字符串、數字等)

  下圖中的兩種寫法其實是同樣的

  

  也就是說,then方法最後返回時,能夠直接用Promise.resolve()/reject()返回一個決議成功/失敗的Promise實例

  另外,Promise的all方法裏,數組中的每一項都會被resolve方法包裹一下,這樣每一項都是一個Promise實例

  2.Promise實例

  

  這裏傳入的Promise實例最後經過resolve方法輸出的仍爲該實例(最底下一行有驗證)

  3.thenable對象

  thenable對象是一個相似於then方法的對象,傳入resolve後,會當即執行其中的then方法,按照then方法的套路走

  

  這裏的執行結果爲「我被執行了」和「哼」

  過程以下:

  1.obj做爲一個thenable對象被傳入的resolve方法,而後後面的then方法執行時,調用obj裏的then方法

  2.這裏的回調函數cb就是console.log(data),也就是輸出哼,但在這以前先輸出「我被執行了」

reject

  而Promise.reject()相比於resolve簡單得多,會把傳入其中的值直接當成錯誤信息輸出

  

應用

  能夠用then變成異步任務並在當前腳本全部同步任務執行後再執行的特性,把同步任務變成異步任務

  

  上方的執行結果爲:我是同步任務、我變成了異步任務、2

  具體過程以下:

  1.用createAsyncTask函數,傳入一個匿名函數,這個函數因爲傳入了Promise的resolve方法,變成了一個Promise實例,可是執行是在後面的then裏,所以變成了異步任務,稍後執行

  2.「我是同步任務」直接輸出

  3.輸出全部同步語句後,對then裏的語句進行執行,因爲這裏兩句都是同步任務,因此按順序輸出

 

綜合案例

  能夠利用Promise的各類方法實現當圖片所有加載完後再載入

  (案例待補充)

相關文章
相關標籤/搜索