ES6 - 整理一下Promise 的用法

王小端coder發表於2019-04-20

Promise 的定義

Pormise是JS的非同步程式設計的一種解決方案,在ES6將其寫進了語言標準,提供了原生的Promise物件。

Promise簡單來理解就是一個容器,裡面存放著某個未來才會結束的事件結果。Promise是一個物件,從它可以獲取非同步操作的訊息,Promise提供了統一的API,各種非同步操作都可以用同樣的方法進行處理。

Promise有下面兩個特點:

  1. 物件的狀態不受外界影響。有三種狀態:padding(進行中)、fulfilled(成功)、rejected(失敗)。只有非同步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。

  2. 一旦狀態改變,就不會再變,任何時候都可以得到這個結果。三個狀態只有從padding到fulfilled或者從padding到rejected。狀態只有從padding改變到fulfilled或者refected,兩種改變。

有了Promise物件,就可以將非同步操作以同步操作的流程表達出來,避免了層層巢狀的回撥函式。此外,Promise物件提供統一的介面,使得控制非同步操作更加容易。

Promise存在的缺點

  1. 無法取消Promise,一旦新建它就會立即執行,無法中途取消。

  2. 如果不設定回撥函式,Promise內部丟擲的錯誤,不會反應到外部。

  3. 當處於pending狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)。

Promise基本用法

const promise = new Promise((resolve, reject) => {
  let status = true;
  if (status) {
    resolve('操作成功!');
  } else {
    reject('操作失敗!');
  }
});

promise.then(res => {
  console.log('成功結果:' + res);
}, error => {
  console.log('失敗結果:' + error);
  
});
複製程式碼

ES6中,Promise物件是一個建構函式,用來生成Promise例項。Promise建構函式接受一個函式作為引數,接受兩個引數,分別是resolve和reject兩個函式。

其中,resolve函式作用是將Promise的狀態從padding改變成fufilled;而reject函式作用是將Promise的狀態從padding改變成rejected。

在Promise例項生產後,可以用then方法分別指定了fufilled狀態和rejected狀態的回撥函式。

其中then方法接受兩個引數,第一個回撥函式是狀態改變fufilled時呼叫的,第二個回撥函式是狀態改變refected時呼叫的。第二個引數是可選的,不一定要提供。

const promise = new Promise((resolve, reject) => {
  console.log('new Promise()');
  resolve();
});

promise.then(() => {
  console.log('resolve()');
});

console.log('End');
複製程式碼

上面是一個Promise對的簡單寫法,我們看下上面的例子是如何輸出的。

// 執行結果
new Promise()
End
resolve()
複製程式碼

在上面的例子中因為Promise物件是同步的所以先輸出,then方法是非同步的所以後輸出。

Promise的語法糖then

Promise例項具有then方法,then方法是定義在原型物件Promise.prototype上的。它的作用前面說過,第一個回撥函式是狀態改變fufilled時呼叫的,第二個回撥函式(可選)是狀態改變rejected時呼叫的。

new Promise((resolve, reject) => {
  resolve('王小端Coder');
}).then(res => {
  console.log(res); // 王小端Coder
});
複製程式碼

then方法的基礎呼叫寫法,可以寫一個回撥方法,來執行成功後的回撥。then方法返回一個的是一個新的Promise例項,因此我們可以採用鏈式寫法,即then方法後面再呼叫一個then方法。

new Promise((resolve, reject) => {
  resolve('王小端Coder');
}).then(res => res).then(res => {
  console.log(res); // 王小端Coder
});
複製程式碼

採用鏈式的then,可以指定一組按照次序呼叫的回撥函式。這時,前一個回撥函式,有可能返回的還是一個Promise物件(即有非同步操作),這時後一個回撥函式,就會等待該Promise物件的狀態發生變化,才會被呼叫。

Promise的語法糖catch

catch是用於指定發生錯誤的回撥函式。

new Promise((resolve, reject) => {
  reject('失敗');
}).catch(error => {
  console.log(error); // 失敗
});
複製程式碼

Promise例項當狀態改變為rejected狀態或者操作失敗丟擲異常錯誤,就會被catch方法捕獲。所以在Promise例項中reject方法等同於丟擲錯誤。如果Promise的狀態已經變成了resolved,再丟擲錯誤無效。

new Promise((resolve, reject) => {
  reject('失敗');
  throw new Error('丟擲異常'); // 這行無效
}).catch(error => {
  console.log(error); // 失敗
});
複製程式碼

Promise的finally方法

finally方法用於指定不管Promis物件最後狀態如何,都會執行的操作。該方法是 ES2018 引入標準的。

new Promise((resolve, reject) => {
  resolve();
}).then(res => {
  console.log('success');
}).catch(error => {
  console.log('error');
}).finally(() =>{
  console.log('finally');
})
複製程式碼

Promise的all方法

Promise.all方法用於將多個Promise例項,包裝成一個新的Promise例項。在all方法中可以傳遞多個Promise物件,當所有的Promise物件狀態都返回fufilled,才會返回fulfilled,否則返回rejected。

const promise1 = new Promise((resolve, reject) => {
  resolve();
})
const promise2 = new Promise((resolve, reject) => {
  resolve();
})
const promise3 = new Promise((resolve, reject) => {
  resolve();
})

const promiseAll = Promise.all([promise1, promise2, promise3]).then(res => {
  console.log('all');
})
複製程式碼

Promise的race方法

Promise.race方法同樣是將多個Promise例項,包裝成一個新的Promise例項。可以傳遞多個Promise物件作為引數,如果例項紅有一個例項率先改變狀態,那麼race的狀態就會跟著改變。

const promise1 = new Promise((resolve, reject) => {
  reject();
})
const promise2 = new Promise((resolve, reject) => {
  resolve();
})
const promise3 = new Promise((resolve, reject) => {
  reject();
})

const promiseRace = Promise.race([promise1, promise2, promise3]).then(res => {
  console.log('race then');
}).catch(error => {
  console.log('race catch');
})
複製程式碼

Promise 結束!謝謝大家能夠指出其中的不足。


相關文章