Promise詳解

1、簡介

  Promise,他是一個對象,是用來處理異步操做的,可讓咱們寫異步調用的時候寫起來更加優雅,更加美觀便於閱讀。顧名思義爲承諾、許諾的意思,意思是使用了Promise以後他確定會給咱們答覆,不管成功或者失敗都會給咱們一個答覆,因此咱們就不用擔憂他跑了哈哈。因此,Promise有三種狀態:pending(進行中),resolved(完成),rejected(失敗)。只有異步返回的結構能夠改變其狀態。因此,promise的過程通常只有兩種:pending->resolved或者pending->rejected。數組

  狀態詳解:promise

(1)promise 從未完成的狀態開始,若是成功它將會是完成態,若是失敗將會是失敗態。
(2)當一個 promise 移動到完成態,全部註冊到它的成功回調將被調用,並且會將成功的結果值傳給它。另外,任何註冊到 promise 的成功回調,將會在它已經完成之後當即被調用。
(3)一樣的,當一個 promise 移動到失敗態的時候,它調用的是失敗回調而不是成功回調。
(4)對包含前進特性的實現來講,promise 在它離開未完成狀態之前的任什麼時候刻,均可以更新它的 progress。當 progress 被更新,全部的前進回調(progress callbacks)會被傳遞以 progress 的值,並被當即調用。前進回調被以不一樣於成功和失敗回調的方式處理;若是你在一個 progress 更新已經發生之後註冊了一個前進回調,新的前進回調只會在它被註冊之後被已更新的 progress 調用。
(5)注意:只有異步操做的結果,能夠決定當前是哪種狀態,任何其餘操做都沒法改變這個狀態。
 

2、使用promises

一、錯誤捕獲

若是在執行器內部拋出了錯誤,那麼 Promise 的拒絕處理函數就會被調用。例如:異步

let promise = new Promise(function(resolve, reject) {
  throw new Error("Explosion!");
});
promise.catch(function(error) {
  console.log(error.message); // "Explosion!"
});

在此代碼中,執行器故意拋出了一個錯誤。此處在每一個執行器以內並無顯式的 try-catch
,所以錯誤就被捕捉並傳遞給了拒絕處理函數。這個例子等價於:函數

let promise = new Promise(function(resolve, reject) {
    try {
        throw new Error("Explosion!");
    } catch (ex) {
        reject(ex);
    }
});
promise.catch(function(error) {
    console.log(error.message); // "Explosion!"
});        


執行器處理程序捕捉了拋出的任何錯誤,以簡化這種常見處理。但在執行器內拋出的錯誤僅
當存在拒絕處理函數時纔會被報告,不然這個錯誤就會被隱瞞。spa

二、建立已決的 Promise

基於 Promise 執行器行爲的動態本質, Promise 構造器就是建立未決的 Promise 的最好方
式。但若你想讓一個 Promise 表明一個已知的值,那麼安排一個單純傳值給 resolve() 函數
的做業並無意義。相反,有兩種方法可以使用指定值來建立已決的 Promise 。
使用 Promise.resolve()
Promise.resolve() 方法接受單個參數並會返回一個處於完成態的 Promise 。這意味着沒有
任何做業調度會發生,而且你須要向 Promise 添加一個或更多的完成處理函數來提取這個參
數值。例如:code

let promise = Promise.resolve(42);
promise.then(function(value) {
  console.log(value); // 42
});

此代碼建立了一個已完成的 Promise ,所以完成處理函數就接收到 42 做爲 value 參數。若
一個拒絕處理函數被添加到此 Promise ,該拒絕處理函數將永不會被調用,由於此 Promise
毫不可能再是拒絕態。
使用 Promise.reject()
你也可使用 Promise.reject() 方法來建立一個已拒絕的 Promise 。此方法像
Promise.resolve() 同樣工做,區別是被建立的 Promise 處於拒絕態,以下:對象

let promise = Promise.reject(42);
promise.catch(function(value) {
  console.log(value); // 42
});

 

三、監視多個 Promise

有時你會想監視多個 Promise的進程,以便決定下一步行動。 ES6 提供了能監視多個 Promise 的兩個方法:
Promise.all() 與 Promise.race() 。blog

Promise.all() 方法:進程

Promise.all() 方法接收單個可迭代對象(如數組)做爲參數,並返回一個 Promise 。這個
可迭代對象的元素都是 Promise ,只有在它們都完成後,所返回的 Promise 纔會被完成。例
如:io

let p1 = new Promise(function(resolve, reject) {
  resolve(42);
});
let p2 = new Promise(function(resolve, reject) {
  resolve(43);
});
let p3 = new Promise(function(resolve, reject) {
  resolve(44);
});
let p4 = Promise.all([p1, p2, p3]);
p4.then(function(value) {
  console.log(Array.isArray(value)); // true
  console.log(value[0]); // 42
  console.log(value[1]); // 43
  console.log(value[2]); // 44
});

此處前面的每一個 Promise 都用一個數值進行了決議,對 Promise.all() 的調用建立了新的
Promise p4 ,在 p1 、 p2 與 p3 都被完成後, p4 最終會也被完成。傳遞給 p4 的完
成處理函數的結果是一個包含每一個決議值( 42 、 43 與 44 )的數組,這些值的存儲順序保
持了待決議的 Promise 的順序(與完成的前後順序無關),所以你能夠將結果匹配到每一個
Promise 。
若傳遞給 Promise.all() 的任意 Promise 被拒絕了,那麼方法所返回的 Promise 就會馬上被
拒絕,而沒必要等待其餘的 Promise 結束:

let p1 = new Promise(function(resolve, reject) {
  resolve(42);
});
let p2 = new Promise(function(resolve, reject) {
  reject(43);
});
let p3 = new Promise(function(resolve, reject) {
  resolve(44);
});
let p4 = Promise.all([p1, p2, p3]);
p4.catch(function(value) {
  console.log(Array.isArray(value)) // false
  console.log(value); // 43
});

在此例中, p2 被使用數值 43 進行了拒絕,則 p4 的拒絕處理函數就馬上被調用,而不會
等待 p1 或 p3 結束執行(它們仍然會各自結束執行,只是 p4 不等它們)。
拒絕處理函數總會接收到單個值,而不是一個數組,該值就是被拒絕的 Promise 所返回的拒
絕值。本例中的拒絕處理函數被傳入了 43 ,反映了來自 p2 的拒絕。

Promise.race() 方法:

Promise.race() 提供了監視多個 Promise 的一個稍微不一樣的方法。此方法也接受一個包含需
監視的 Promise 的可迭代對象,並返回一個新的 Promise ,但一旦來源 Promise 中有一個被
解決,所返回的 Promise 就會馬上被解決。與等待全部 Promise 完成的 Promise.all() 方法
不一樣,在來源 Promise 中任意一個被完成時, Promise.race() 方法所返回的 Promise 就能
做出響應。例如:

let p1 = Promise.resolve(42);
let p2 = new Promise(function(resolve, reject) {
  resolve(43);
});
let p3 = new Promise(function(resolve, reject) {
  resolve(44);
});
let p4 = Promise.race([p1, p2, p3]);
p4.then(function(value) {
  console.log(value); // 42
});

在此代碼中, p1 被建立爲一個已完成的 Promise ,而其餘的 Promise 則須要調度做業。
p4 的完成處理函數被使用數值 42 進行了調用,並忽略了其餘的 Promise 。傳遞給
Promise.race() 的 Promise 確實在進行賽跑,看哪個首先被解決。若勝出的 Promise 是被
完成,則返回的新 Promise 也會被完成;而勝出的 Promise 如果被拒絕,則新 Promise 也會
被拒絕

四、串聯 Promise

存在多種方式來將 Promise 串聯在一塊兒,以完成更復雜的異步行爲。
每次對 then() 或 catch() 的調用實際上建立並返回了另外一個 Promise ,僅當前一個
Promise 被完成或拒絕時,後一個 Promise 纔會被決議

在 Promise 鏈中返回值

Promise 鏈的另外一重要方面是能從一個 Promise 傳遞數據給下一個 Promise 的能力。傳遞給
執行器中的 resolve() 處理函數的參數,會被傳遞給對應 Promise 的完成處理函數,這點你
前面已看到過了。你能夠指定完成處理函數的返回值,以便沿着一個鏈繼續傳遞數據。例
如:

let p1 = new Promise(function(resolve, reject) {
  resolve(42);
});
p1.then(function(value) {
  console.log(value); // "42"
  return value + 1;
}).then(function(value) {
  console.log(value); // "43"
});

p1 的完成處理函數在被執行時返回了 value + 1 。因爲 value 的值爲 42 (來自執行
器),此完成處理函數就返回了 43 。這個值隨後被傳遞給第二個 Promise 的完成處理函數,
並被其輸出到控制檯。

在 Promise 鏈中返回 Promise

從完成或拒絕處理函數中返回一個基本類型值,可以在 Promise 之間傳遞數據,但若你返回
的是一個對象呢?若該對象是一個 Promise ,那麼須要採起一個額外步驟來決定如何處理。
研究如下例子:

let p1 = new Promise(function(resolve, reject) {
  resolve(42);
});
let p2 = new Promise(function(resolve, reject) {
  resolve(43);
});
p1.then(function(value) {
  // 第一個完成處理函數
  console.log(value); // 42
  return p2;
}).then(function(value) {
  // 第二個完成處理函數
  console.log(value); // 43
});

在此代碼中, p1 安排了一個決議 42 的做業, p1 的完成處理函數返回了一個已處於決議態的 Promise : p2 。因爲 p2 已被完成,第二個完成處理函數就被調用了。而若 p2 被拒絕,會調用拒絕處理函數(若是存在的話),而不調用第二個完成處理函數。

相關文章
相關標籤/搜索