Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。它由社區最先提出和實現,ES6 將其寫進了語言標準,統一了用法,原生提供了 Promise 對象。javascript
所謂 Promise,簡單說就是一個容器,裏面保存着某個將來纔會結束的事件(一般是一個異步操做)的結果。從語法上說,Promise 是一個對象,從它能夠獲取異步操做的消息。Promise 提供統一的 API,各類異步操做均可以用一樣的方法進行處理。html
Promise 對象有如下兩個特色:java
使用 Promise 對象的好處在於:編程
Promise 缺點:數組
ES6 規定,Promise 對象是一個構造函數,用來生成 Promise 實例。promise
const promise = new Promise((resolve, reject) => { setTimeout(() => { const num = Math.random(); if (num > 0.5) { resolve(num); } else { reject(num); } }, 500); }); promise.then( res => { console.log("成功:" + res); }, err => { console.log("失敗:" + err); } );
Promise 構造函數接受一個函數做爲參數,該函數的兩個參數分別是 resolve 和 reject。它們是兩個函數,由 JavaScript 引擎提供,不用本身部署。dom
const promise = new Promise((resolve, reject) => { setTimeout(() => { const num = Math.random(); if (num > 0.5) { resolve(num); } else { reject(num); } }, 500); }); promise .then(res => { console.log("成功:" + res); }) .catch(err => { console.log("失敗:" + err); }); promise .then(res => { console.log("成功:" + res); throw new Error("test"); }) .catch(err => { // num > 0.5時打印 "失敗:Error: test" console.log("失敗:" + err); });
Promise 新建後當即執行,then 方法指定的回調函數,將在當前腳本全部同步任務執行完纔會執行,catch 同理。異步
調用 resolve 或 reject 並不會終結 Promise 的參數函數的執行。異步編程
const promise = new Promise((resolve, reject) => { console.log("我是第一個執行的"); resolve(); }); promise.then(res => { console.log("我是第三個執行的"); }); console.log("我是第二個執行的");
reject 函數的參數一般是 Error 對象的實例,表示拋出的錯誤;resolve 函數的參數除了正常的值之外,還多是另外一個 Promise 實例。函數
若是一個 Promise(P2) 的 resolve 參數是另外一個 Promise(P1),此時 P1 的狀態就會傳給 P2,P1 的狀態決定了 P2 的狀態,P1 的狀態改變,P2 的回調函數纔會執行。
const p1 = new Promise(function(resolve, reject) { setTimeout(() => reject(new Error("fail")), 3000); }); const p2 = new Promise(function(resolve, reject) { setTimeout(() => resolve(p1), 1000); }); p2.then(result => console.log(result)).catch(error => console.log(error)); // Error: fail
上面代碼中,p1 是一個 Promise,3 秒以後變爲 rejected。p2 的狀態在 1 秒以後改變,resolve 方法返回的是 p1。因爲 p2 返回的是另外一個 Promise,致使 p2 本身的狀態無效了,由 p1 的狀態決定 p2 的狀態。因此,後面的 then 語句都變成針對後者(p1)。又過了 2 秒,p1 變爲 rejected,致使觸發 catch 方法指定的回調函數。
then 方法能夠返回一個新的 Promise 實例(注意,不是原來那個 Promise 實例)。所以能夠採用鏈式寫法,即 then 方法後面再調用另外一個 then 方法。
const promise = new Promise((resolve, reject) => { resolve("promise"); }) .then(res => { console.log(res); // promise return "promise1"; }) .then(res => { console.log(res); // promise1 return "promise2"; }) .then(res => { console.log(res); // promise2 });
注意:只要一個 Promise 中拋出錯誤,將執行 catch 方法,then 鏈終止。
const promise = new Promise((resolve, reject) => { resolve("promise"); }) .then(res => { console.log(res); // promise throw new Error("停止"); return "promise1"; }) .then(res => { console.log(res); return "promise2"; }) .then(res => { console.log(res); }) .catch(err => { console.log(err); // Error: 停止 });
主動終止 then 鏈,經過 catch 方法來停止 promise chain
const promise = new Promise((resolve, reject) => { resolve("promise"); }) .then(res => { console.log(res); // promise return Promise.reject({ notRealPromiseException: true }); }) .then(res => { console.log(res); return "promise2"; }) .then(res => { console.log(res); }) .catch(err => { if (err.notRealPromiseException) { return true; } console.log(err); });
finally 方法用於指定無論 Promise 對象最後狀態如何,都會執行的操做。該方法是 ES2018 引入標準的。
finally 本質上是 then 方法的特例,不接受任何參數,不依賴於 Promise 的執行結果
promise.finally(() => { // 語句 }); // 等同於 promise.then( result => { // 語句 return result; }, error => { // 語句 throw error; } );
Promise.all 方法用於將多個 Promise 實例,包裝成一個新的 Promise 實例。
const promise = Promise.all([promise1, promise2, promise3])
Promise.all 方法接受一個數組做爲參數,promise、pro 米色、promise3 都是 Promise 實例,若是不是,就會先調用下面講到的 Promise.resolve 方法,將參數轉爲 Promise 實例,再進一步處理。(Promise.all 方法的參數能夠不是數組,但必須具備 Iterator 接口,且返回的每一個成員都是 Promise 實例。瞭解 Iterator 接口)
promise 的狀態由 promise一、promise二、promise3 決定,分紅兩種狀況。
const p1 = new Promise((resolve, reject) => { resolve("hello"); }) .then(result => result) .catch(e => e); const p2 = new Promise((resolve, reject) => { throw new Error("報錯了"); }) .then(result => result) .catch(e => e); Promise.all([p1, p2]) .then(result => console.log(result)) .catch(e => console.log(e)); // ["hello", Error: 報錯了]
上面代碼中,p1 會 resolved,p2 首先會 rejected,可是 p2 有本身的 catch 方法,該方法返回的是一個新的 Promise 實例,p2 指向的其實是這個實例。該實例執行完 catch 方法後,也會變成 resolved,致使 Promise.all()方法參數裏面的兩個實例都會 resolved,所以會調用 then 方法指定的回調函數,而不會調用 catch 方法指定的回調函數。
若是 p2 沒有本身的 catch 方法,就會調用 Promise.all()的 catch 方法。
Promise.race 方法一樣是將多個 Promise 實例,包裝成一個新的 Promise 實例。
const p = Promise.race([p1, p2, p3])
只要 p一、p二、p3 之中有一個實例率先改變狀態,p 的狀態就跟着改變。那個率先改變的 Promise 實例的返回值,就傳遞給 p 的回調函數。
Promise.race 方法的參數與 Promise.all 方法同樣,若是不是 Promise 實例,就會先調用下面講到的 Promise.resolve 方法,將參數轉爲 Promise 實例,再進一步處理。
將現有對象轉化爲 Promise 對象。
const promise = Promise.resolve('Hello world')
let thenObj = { then(resolve, reject) { resolve("Hello"); } }; const promise = Promise.resolve(thenObj); promise.then(res => { console.log(res); // Hello });
Promise.reject(reason)方法也會返回一個新的 Promise 實例,該實例的狀態爲 rejected。