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的執行函數後面
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暫時沒有解決方法
Promise實例中還有個finally方法,能夠放在鏈式調用的最後,其中的代碼不管如何都會執行
注意若是finally執行時還有錯誤未處理,則會報錯,說明Promise裏的錯誤未處理
Promise提升了代碼的可讀性和可維護性
Promise的使用最大的好處是,解決了以前多層嵌套回調的問題
例如,咱們須要建立一個回調函數,用來在1s後執行咱們傳入的一個函數,若是說只是回調一次,直接調用這個回調函數,傳入1s後執行的函數,便可
但若是是要依賴上一次回調的結果,再去執行一次回調函數,那就須要嵌套兩層了,不過也還行
可若是是嵌套到五六層呢?嵌套了這麼多層之後,若是須要更改其中兩次的執行順序呢?彷佛就沒辦法操做了,堪稱回調地獄(以下圖)
可若是使用Promise對象來寫這一段代碼,就變成了下面的樣子
相比於以前的層層套的寫法,這裏採用了鏈式調用的方法,若是哪裏須要修改內容或順序,能夠直接修改then裏的內容,或者調整then的順序,解決了多層嵌套的問題
用來接收一個數組,裏面每一項是一個Promise實例,最後包裝成一個新的Promise實例
注意這裏傳入的必須是數組(可迭代),不然會報錯(not iterable)
分三種狀況:
1.全部的Promise決議爲成功,.all的決議也爲成功,把全部Promise實例的resolve中傳入的參數組成一個數組返回,其順序符合Promise實例的順序
2.有一個Promise決議爲失敗,.all決議爲失敗,把這個決議失敗的reject傳入的參數做爲錯誤返回
有多個Promise決議爲失敗時,輸出的參數只有第一個reject傳入的參數
3.傳入空數組,決議爲成功,輸出then中給resolve傳入的參數
相似於all,race裏傳入的參數也是Promise實例,不過返回時,按照第一個返回的決議決定race的決議狀況,執行then裏的resolve或reject
若是返回的速度同樣,則按照傳入時的第一個Promise實例的決議來決定執行resolve/reject
但若是傳入的爲空,則什麼都不執行,會一直「掛」在那裏
這裏的resolve和reject不是Promise實例或者then裏傳入的參數,而是Promise實例的方法,用來生成被決議爲成功/失敗的Promise實例
也就是說,不管傳入的是什麼,resolve/reject返回的都是一個Promise實例
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),也就是輸出哼,但在這以前先輸出「我被執行了」
而Promise.reject()相比於resolve簡單得多,會把傳入其中的值直接當成錯誤信息輸出
能夠用then變成異步任務並在當前腳本全部同步任務執行後再執行的特性,把同步任務變成異步任務
上方的執行結果爲:我是同步任務、我變成了異步任務、2
具體過程以下:
1.用createAsyncTask函數,傳入一個匿名函數,這個函數因爲傳入了Promise的resolve方法,變成了一個Promise實例,可是執行是在後面的then裏,所以變成了異步任務,稍後執行
2.「我是同步任務」直接輸出
3.輸出全部同步語句後,對then裏的語句進行執行,因爲這裏兩句都是同步任務,因此按順序輸出
能夠利用Promise的各類方法實現當圖片所有加載完後再載入
(案例待補充)