目錄
1. 概述
Promise 是異步編程的一種解決方案。ES6 原生提供了Promise
對象。
Promise
對象是一個代理對象,被代理的值在Promise
對象創建時可能是未知的。它允許爲異步操作的成功和失敗分別綁定相應的處理方法。
一個Promise
有以下幾種狀態:
- pending:初始狀態
- fulfilled:操作成功
- rejected:操作失敗
Promise
對象具有以下特點:
- 對象的狀態不受外界影響。只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。
- 一旦狀態改變,就不會再變,任何時候都可以得到這個結果。
Promise
對象的狀態改變,只有兩種可能:從pending
變爲fulfilled
和從pending
變爲rejected
。只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果,這時就稱爲 resolved。
2. 基本用法
Promise
對象是一個構造函數,用來生成Promise
實例。
var promise = new Promise(function(resolve, reject){
...
})
Promise
構造函數接受一個函數作爲參數,Promise
構造函數執行時立即調用該函數。該函數的兩個參數分別是resolve
函數和reject
函數。
resolve
函數:將Promise
對象的狀態從pending
變爲fulfilled
,在異步操作成功的時候會調用,並且將異步操作的結果作爲參數傳遞。
reject
函數:將Promise
對象狀態從pending
變爲rejected
,在異步操作失敗時會調用,並且將異步操作報出的錯誤作爲參數傳遞。
Promise
實例生成以後,可以用then
方法分別指定fulfilled
狀態和rejected
狀態的回調函數。
promise.then(onFulfilled[, onRejected]);
then
方法可以接受兩個回調函數作爲參數。第一個回調函數是Promise
對象的狀態變爲fulfilled
時調用,第二個回調函數是Promise
對象的狀態變爲rejected
時調用(可選)。
下面是一個簡單的例子。
// 創建Promise實例
function promise(second) {
return new Promise((resolve, reject) => setTimeout(resolve, second, "成功!"))
}
promise(100).then(value = > console.log(value)); // “成功!“”
上面代碼中,promise
方法返回一個Promise
實例,內部使用定時器模擬了一個異步任務。當過了指定時間後,Promise
實例狀態變爲fulfilled
,就會觸發then
方法綁定的回調函數。
下面是一個異步加載圖片的例子。
function imgLoad(url) {
// 返回Promise實例
return new Promise((resolve, reject) => {
// 創建XMLHttpRequest實例
var request = new XMLHttpRequest();
// 設置連接信息
request.open("GET",url);
// 返回二進制對象
request.responseType = 'blob';
request.onreadystatechange = function() { // 監聽狀態變化
if(request.readyState === 4 && request.status === 200) { // 通信完成
return resolve(request.response);
}else{
return reject(Error("圖片加載失敗!" + request.statusText))
}
}
request.onerror = function(){ // 請求失敗監聽
return reject(Error("請求失敗!"))
}
// 發送請求
request.send();
})
}
// 執行then方法
imgLoad("url").then(((response => console.info(response)), (error => console.info(error))));
3. Promise 對象實例方法
3.1 Promise.prototype.then()
then()
方法返回一個 Promise
實例,可以爲Promise
實例添加狀態改變的回調函數。由於then()
方法返回一個promise
實例,所以可以進行鏈式調用。
語法
// 創建Promise實例
var promise = new Promise(function(resolve, reject){
...
})
// then方法參數是兩個回調函數
promise.then(onFulfilled[, onRejected]);
參數
以下是傳遞給then()
方法的參數:
- onFulfilled:當
Promise
實例狀態變爲fulfilled
時調用的函數,該參數可選。 - onRejected:當
Promise
實例狀態變爲rejected
時調用的函數,該參數可選。
返回值
當一個 Promise
狀態發生改變時,返回函數將被異步調用。具體的返回值依據以下規則返回。如果 then 中的回調函數:
- 返回了一個值,那麼
then
方法返回的Promise
將會成爲fulfilled
,並且將返回的值作爲fulfilled
狀態的回調函數的參數值。 - 沒有返回任何值,那麼
then
方法返回的Promise
將會成爲fulfilled
,並且該fulfilled
狀態的回調函數的參數值爲undefined
。 - 拋出一個錯誤,那麼
then
返回的Promise
將會成爲rejected
,並且將拋出的錯誤作爲rejected
狀態的回調函數的參數值。 - 返回一個已經是
fulfilled
狀態的Promise
,那麼then
返回的Promise
也會成爲fulfilled
,並且將那個Promise
的fulfilled
狀態的回調函數的參數值作爲該被返回的Promise
的fulfilled
狀態回調函數的參數值。 - 返回一個已經是拒絕狀態的
Promise
,那麼then
返回的Promise
也會成爲’rejected’,並且將那個Promise
的rejected
狀態的回調函數的參數值作爲該被返回的Promise
的rejected
狀態回調函數的參數值。 - 返回一個
pending
狀態的Promise
,那麼then
返回Promise
的狀態也是fulfilled
的,並且它的終態與那個Promise
的終態相同;同時,它變爲終態時調用的回調函數參數與那個Promise
變爲終態時的回調函數的參數是相同的。
3.2 Promise.prototype.catch()
catch()
方法返回一個Promise
實例,並且處理拒絕的情況。它的行爲與調用Promise.prototype.then(undefined, onRejected)
相同。
語法
var promise = new Promise(function(resolve, rejected){
...
})
promise.catch(onRejected);
參數
以下是傳遞給catch()
方法的參數:
- onRejected:當
Promise
被rejected
時,被調用的一個函數。
返回值
一個Promise
實例。
示例
var p1 = new Promise((resolve, reject) => {
resolve('Success');
});
p1.then((value) => {
throw Error("錯誤");
}).catch((error) => {
console.log(error); // Error: 錯誤
}).then(() =>{
console.log("sucess!") // sucess!
}, () => {
console.log("error");
});
3.3 Promise.prototype.finally()
finally
方法用於指定不管 Promise
對象最後狀態如何,都會執行的操作。
var promise = new Promise(function(resolve, rejected){
...
})
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
finally
方法接受一個回調函數作爲參數,但是該回調函數不接受任何參數。
finally
本質上是then
方法的特例。
promise
.finally(() => {
...
});
// 等價於
promise
.then(
result => {
...
return result;
},
error => {
...
throw error;
}
);
4. Promise 對象方法
4.1 Promise.all()
Promise.all()
方法用於將多個 Promise
實例,包裝成一個新的Promise
實例。
const promise = Promise.all([p1, p2, p3]);
上面代碼中,Promise.all()
接受一個數組作爲參數,數組成員p1
,p2
,p3
都是Promise
實例。如果不是,就會將參數轉爲Promise
實例,再進行處理。另外,Promise.all()
方法的參數可以不是數組,但必須具有 Iterator
接口。
promise
的狀態由p1
,p2
,p3
決定,分爲兩種情況:
p1
,p2
,p3
的狀態都變成fulfilled
,promise
的狀態纔會變成fulfilled
,此時p1
、p2
、p3
的返回值組成一個數組,傳遞給promise
的回調函數。- 只要
p1
、p2
、p3
之中有一個被rejected
,promise
的狀態就變成rejected
,此時第一個被reject
的實例的返回值,會傳遞給promise
的回調函數。
示例
var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'foo');
});
Promise.all([p1, p2, p3]).then(values => {
console.log(values); // [3, 1337, "foo"]
});
上面例子紅,Promise.all
等待所有都完成(或第一個失敗)時纔會調用後面的回調函數。
4.2 Promise.race()
Promise.race()
方法同樣是將多個 Promise
實例,包裝成一個新的 Promise
實例。
const p = Promise.race([p1, p2, p3]);
上面代碼中,只要p1
、p2
、p3
之中有一個實例率先改變狀態,p
的狀態就跟着改變。那個率先改變的 Promise
實例的返回值,就傳遞給p
的回調函數。
Promise.race()
方法的參數與Promise.all()
方法一樣,如果不是 Promise
實例,參數會轉爲 Promise
實例,再進一步處理。
示例
var p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, "one");
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, "two");
});
Promise.race([p1, p2]).then(function(value) {
console.log(value); // "two"
// 兩個都完成,但 p2 更快
});
var p3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, "three");
});
var p4 = new Promise(function(resolve, reject) {
setTimeout(reject, 500, "four");
});
Promise.race([p3, p4]).then(function(value) {
console.log(value); // "three"
// p3 更快,所以它完成了
}, function(reason) {
// 未被調用
});
var p5 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, "five");
});
var p6 = new Promise(function(resolve, reject) {
setTimeout(reject, 100, "six");
});
Promise.race([p5, p6]).then(function(value) {
// 未被調用
}, function(reason) {
console.log(reason); // "six"
// p6 更快,所以它失敗了
});
4.3 Promise.resolve()
Promise.resolve()
方法將現有對象轉爲一個Promise
實例。
const promise = Promise.resolve(12);
Promise.resolve
方法的參數分成四種情況:
- 參數是一個
Promise
實例,那麼Promise.resolve
將不做任何修改、原封不動地返回這個實例。 - 參數是一個
thenable
對象,即具有then
方法的對象,Promise.resolve
方法會將這個對象轉爲Promise
對象,然後就立即執行thenable
對象的then
方法。 - 如果參數是一個原始值,或者是一個不具有
then
方法的對象,則Promise.resolve
方法返回一個新的Promise
對象,狀態爲fulfilled
。 - 不帶有任何參數,直接返回一個
fulfilled
狀態的Promise
對象。
示例
Promise.resolve("Success").then(function(value) {
console.log(value); // "Success"
}, function(value) {
// 不會被調用
});
Promise.resolve([1,2,3]).then(function(v) {
console.log(v[0]); // 1
});
4.4 Promise.reject()
Promise.reject()
方法返回一個帶有拒絕原因的Promise
對象。
示例
Promise.reject(new Error('fail')).then(function() {
// not called
}, function(error) {
console.error(error); // Stacktrace
});
5 參考鏈接
本篇博文是我自己學習筆記,原文請參考:ECMAScript 6 入門,MDN網站。
如有問題,請及時指出!
歡迎溝通交流,郵箱:[email protected]。