《淺談 JavaScript 異步編程 Promise 的使用》要點:
本文介紹了淺談 JavaScript 異步編程 Promise 的使用,希望對您有用。如果有疑問,可以聯系我們。
Promise 是異步編程的一種辦理方案.簡單來說 Promise 就是一個容器,里面保存著某個未來才會結束的異步操作的結果.
從語法上說,Promise 是一個對象,通過它可以獲取異步操作的消息.
在談論 Promise 之前我們先看一段代碼:
在日常開發中,我們經常會處理一些異步操作,例如:發送 Ajax 哀求,setTimeout 等.處理這些異步操作我們一般會傳遞一個回調函數,然而當我們要進行一連串的異步順序操作的時候,回調代碼就會自動往右邊進行偏離,就像金字塔那樣.相信你已經遇到過,這就是我們常常說的“金字塔回調”.
首先,從視覺看,金字塔回調會有多層的嵌套回調函數,結尾會有大量的花括號和圓括號,例如上述代碼.并且,這樣寫出來的代碼不優雅,閱讀起來也比擬費力,我們也無法在內部使用 throw new Error() 并在外部進行捕獲異常.
Promise 的出現就是為了主要辦理這兩個主要問題:它可以讓我們以同步的方式編寫異步代碼,同時我們也可以優雅的捕獲錯誤和異常.
Promise 最初起源于社區,現在已經被寫入了 ES6 的規范中,而且主流瀏覽器都已經開始支持了,所以本文就介紹在代碼中如何使用 Promise.
Promise 是一個構造函數,使用時我們必要先使用 new 創建一個 Promise 實例.
在上面代碼中我們可以看到:
1)構造函數接受一個函數作為參數,該函數有兩個參數resolve和reject, 它們是兩個函數.
2)resolve 函數與 reject 函數的作用:
resolve函數:將Promise對象的狀態從 “未完成”變為 “勝利”(Pending -> Resolved),在異步操作勝利時調用,并將異步操作的結果,作為參數傳遞出去
reject 函數:將Promise對象的狀態從 “未完成” 變為 “失敗”(Pending -> Rejected),在異步操作失敗時調用,并將異步操作報出的差錯作為參數傳遞出去.
3)Promise 實例生成以后,可以用then辦法 指定 Resolved 狀態和 Rejected 狀態的回調函數.
其中 resolve 函數的參數除了正常的值以外,還可能是另一個 Promise 實例,表現異步操作的結果可能是一個值,也有可能是另一個異步操作.
這時 Promise 實例通過 then 指定的回調會等待另一個 Promise 實例狀態產生變化后才會進行調用.
上述成果是:promise2 等待 2s 之后輸出了 promise 中的值.
這時 promise 的狀態會傳遞給 promise2, promise 的狀態決定了 promise2 的狀態.
Promise對象有三種狀態
?Pending (進行中)
?Resolved (已完成)
?Rejected (已失敗)
Promise的狀態變化有上圖兩條路徑:
resolve 辦法會使 Promise 對象由 Pending 狀態變為 Resolved 狀態
reject 辦法或異常會使得 Promise 對象由 pending 狀態變為 Rejected 狀態
對象狀態一旦改變,任何時候都能得到這個結果.即狀態一旦進入 Resolved 狀態或者 Rejected 狀態, Promise 對象便不再出現狀態變化,同時我們再添加回調會立即得到結果.這點跟變亂不一樣,變亂是發生后再綁定監聽,就監聽不到了.
Promise 實例生成以后,可以用 then 為實例添加狀態改變時的回調函數.
getData 函數返回一個 promise 實例,使用 then 為它指定一個 Resolved 狀態的回調函數, 異步哀求中傳給 resolve 的值,將作為回調函數中的參數.當異步哀求成功之后,回調函數變會執行輸出對應的值.
假設異步哀求失敗了怎么辦? then 其實還可以指定第二個可選的參數,即Rejected 狀態的回調函數.
在上述例子中,異步哀求成功后,第一個回調函數會執行,如果失敗了,第二個回調函數便會執行.
其實我們還可以使用 catch 指定差錯時的回調,catch 調用其實等同于使用then(undefined, function) .
鏈式挪用
我們已經知道了,使用 then 可以為 promise 實例添加狀態改變的回調函數.其實,我們還可以使用 then 進行鏈式調用來指定一組依照順序執行的回調函數,因為 then 的調用總是會返回 promise 的一個新的實例.
其中后一個 promise 實例會依賴上一個 promise 實例的狀態,如果上一個promise 實例狀態是 Rejected,則后面的 promise 實例狀態也是 Rejected.如果前一個回調函數返回的是一個 promise 對象(有異步操作),這時后一個回調函數會等待該 promise 對象狀態產生變化時,才會進行調用.
promise 對象的錯誤具有冒泡性質,會一直向后傳遞,直到捕捉為止.錯誤總是會被下一個 catch 語句捕捉.
一般來說,不要在 then 辦法里面定義 Reject 狀態的回調函數,總是使用 catch捕獲錯誤.
Promise與循環
前面提到了 Promise 可以指定一組異步操作順序執行,那如果我們需要等待一組異步操作之后結束之后再執行呢?Promise 提供了一個很方便的辦法Promise.all.
Promise.all 辦法用于將多個 Promise 實例,包裝成一個新的 Promise 實例.
Promise.all 辦法接受一個 promise 實例數組作為參數(可以不是數組,但需要具有 iterator 接口), 如果元素不是 Promise 實例,就會先調用Promise.resolve 辦法,將參數轉為 Promise 實例,再進一步處理.
Promise.all 辦法返回的 Promise 實例狀態分為兩種情況:
實例數組中所有實例的狀態都釀成 Resolved,Promise.all 返回的實例才會釀成 Resolved, 并將 Promise 實例數組的所有返回值組成一個數組,傳遞給回調函數.
實例數組中某個實例變為了 Rejected 狀態,Promise.all 返回的實例會立即變為 Rejected 狀態.并將第一個 Rejected 的實例的返回值傳遞給回調函數.
Promise.race 辦法跟 Promise.all 辦法差不多.唯一的區別在于該辦法返回的Promise 實例并不會等待所有 Proimse 都跑完,而是只要有一個 Promise 實例改變狀態,它就跟著改變狀態.并使用第一個改變狀態實例的返回值作為返回值.
Promise 已經被寫入 ES6 規范中.由下圖可以看出,各年夜瀏覽器(除IE外)都已開始支持原生 Promise 的使用.但是在低版本瀏覽器和運行環境中,并不支持 Promise 對象.
要在這些環境中使用 Promise,則必要借助一些兼容 Promise 的類庫.ES6 中的 Promise 規范來源于 Promises/A+ 社區,因此,在選擇類庫時應該考慮對Promise/A+ 兼容性.
Promise 的 Polyfill 類庫有很多,筆者常常使用的有(供參考):
es6-promise
bluebird
參考文獻:https://promisesaplus.com/
本文作者:張寧(點融黑幫),就職于點融網工程部 social team 立異社.熱愛前端,熱愛技術.
本文由@點融黑幫(ID:DianrongMafia)原創宣布于今日頭條,未經許可,禁止轉載.
維易PHP學堂逐步分享更多《淺談 JavaScript 異步編程 Promise 的使用》相關教程。歡迎交流
轉載請注明本頁網址:
http://www.snjht.com/jiaocheng/9120.html