Promise再回首-- 再深刻點了解異步編程

菲菲古裝
以前寫代碼時,通常處理異步都是async-await一把梭,相比回調處理會舒服不少,用得時候如魚得水, 可是真要深究其原理就迷迷糊糊了。 因此今天須要去探尋一下Promise的真諦(async-await本質上是Promise的語法糖)。

爲何要使用Promise

想想,咱們以前是怎麼處理異步編程的(回調函數和事件),基於回調函數的異步編程一般代碼冗雜,層層嵌套,不易於維護,甚至可能形成‘回調地獄’的慘狀。
Promise則是另一種異步編程的方案,它比回調函數更優雅美觀,也更易於維護。起初有各大社區實現Promise的功能,到ES6的時候,TC39將Promise方案寫進了標準之中,統一實現,在原生的層面上實現了Promise。編程

怎麼去理解Promise

這邊參照阮大大的想法,咱們能夠把Promise理解成一個容器,容器會保存異步操做(好比http請求或者定時器setTimeout)的結果(resolved或rejected),咱們能夠經過Promise的相關方法獲取異步操做的完成結果或者捕獲其錯誤。數組

Promise通常有一下三種狀態可能:pendingfullfilled(resolved)rejected,以及兩種狀態過渡: fullfilled 到 resolvedfullfilled到rejected。因此promise對象通常有兩種結果狀態:1. resolved(完成),2.rejected(失敗),並且Promise的結果狀態是肯定以後就沒法改變的。promise

基本用法

promise實例

promise對象由Promise構造函數實例後生成。bash

const pro = new Promise( (resolve,reject) => {
   // xhr 請求
   // 請求成功後 resolve 結果
   // 請求遇到問題 reject 錯誤信息
})
複製代碼

Promsie構造器接收一個帶有resolve和reject兩個參數(也是函數)的函數(一般裏面包含了異步操做)。實例化構造函數時,會直接調用該函數,異步操做也將會被觸發。異步

當異步操做取得結果時,咱們能夠resolve這個promise實例,將promise的狀態從fullfilled轉變爲resolved,並將結果做爲參數傳遞給promise實例。 一樣若是異步操做發生錯誤時,咱們能夠reject這個promise實例,將promise的狀態從fullfilled轉爲rejected狀態,並將錯誤信息做爲參數傳遞給promise實例。async

promise實例的then與catch方法

promise對象提供了thencatch方法(Promise原型鏈上的方法),方便咱們對promise狀態發生改變時,對所接受到的信息進行處理。異步編程

pro.then( res => {
   // 這裏的res就是resolve該promise時所傳遞的數據
    console.log(res);
})
.catch(error => {
   // 這裏的error就是reject該promise時所捕獲的錯誤信息
   console.log(error);
   
})
複製代碼

then方法須要傳遞一個函數,當promise狀態變爲resolved時,將會調用該函數,並將傳遞的數據做爲參數。同理promise狀態變爲rejected時,catch的方法會被調用,且promise中捕獲的錯誤將會被做爲參數。函數

注意ui

then方法返回的是一個promise對象,具體返回的promise取決於then方法中的回調函數的返回值。由於這種機制,因此promise能夠鏈式調用then方法,也就能夠將依賴前一個異步結果的then方法返回,而後繼續處理。 then方法的返回依據參考 mdn文檔 then方法返回值spa

注意

catch方法會捕獲其以前在promise鏈式調用時拋出的錯誤,而不單單只是promise自己拋出的錯誤。 還有一點,promise內部的錯誤若是不被reject,錯誤不會被顯性得拋出,catch也得不到錯誤信息。

catch方法會返回一個promise,因此其後面也可使用鏈式調用。

pro
.then(res => {
  // 這裏的res就是resolve該promise時所傳遞的數據
  console.log(res);
  const pro1 = new Promise((resolve, reject) => {
    // 一些 xhr 請求
    // 請求成功後 resolve
    // 請求遇到問題 reject
  });
  return pro1
})
.then(res1 => {
  // 這裏處理 pro1成功處理的相關數據
  console.log(res1);
})
.catch(error => {
  // 這裏的error就是promise鏈式調用時所拋出的錯誤信息
  console.log(error);
});

複製代碼

Promise構造器自己方法

Promise.all

const p = Promise.all([p1, p2, p3]);
複製代碼

all方法須要傳入一組promise實例做爲參數,all方法自己會返回一個promise實例(p),p的狀態取決於傳入的promise組。

  1. 若是傳入的promise組中全部的promise都是resolved狀態,那麼p的狀態也將變爲resolved,此時promise組的返回值合併爲數組傳遞給p
  2. 若是傳入的promise組中有一個promise爲rejected狀態時,那麼p的狀態將變爲rejected,此時rejected拋出的錯誤將傳遞給p

Promise.race

const p = Promise.race([p1, p2, p3]);
複製代碼

與all類似,須要傳入promise組,可是p的狀態改變模式不太同樣。 promise組中任意一個promise狀態變爲resolved時,race方法返回的promise將會把狀態改成resolved。

Promise.allSettled(兼容性較差)

const p = Promise.allSettled([p1, p2, p3]);
複製代碼

與all類似,須要傳入promise組,可是p的狀態改變模式也不太同樣。 p將會在promise組中全部promise從fullfilled狀態轉變爲rejected或resolved時,轉變爲resolved轉態,promise組返回值或者拋出的錯誤以數組的方式傳遞給p。

Promise.resolve()

const p = Promise.resolve();
複製代碼

簡單來講,resolve方法返回是promise對象,具體須要看傳入的參數是什麼

  1. 若是傳入是一個promise,則返回這個promise
  2. 若是傳入的不是promise也不是thenable對象,就返回狀態爲resolved的,解析值爲傳入參數的promise對象
  3. 若是什麼都不傳入,就返回一個狀態爲resolved的promise對象
  4. 還有一個thenable對象狀況

Promise.reject()

const p = Promise.reject();
複製代碼

reject方法會返回一個狀態爲rejected的promise對象,reject值爲方法傳入的參數。

最後

好了,到這裏已經把Promise比較基礎的部分都梳理了一遍,若是有不懂或者有問題的部分能夠評論!複製代碼
相關文章
相關標籤/搜索