Promise 是非同步程式設計的解決方案,它可以很方便的處理非同步事件。一個 Promise 例項包含一個非同步操作,這項非同步操作只有三種狀態,pending
初始狀態,既不是成功,也不是失敗狀態,Resolved
成功完成,Rejected
非同步操作失敗。
Promise 的狀態不受外界影響而且一旦狀態改變,就不會再改變。
建立 Promise
要建立 Promise 例項要用到 Promise 類,它接受一個函式作為引數,函式接受兩個引數,這兩個引數也是函式,一個是當非同步成功執行時需要呼叫的函式,一個是失敗時呼叫的函式。
建立 Promise 例項的引數函式,將會立即執行。
function getData(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onload = () => resolve(xhr.responseText);
// 將狀態變為 Resolved 並傳入獲取到的資料
xhr.onerror = () => reject(xhr.statusText);
// 將狀態變為 Rejected 並傳入錯誤資訊
xhr.send();
})
}
//呼叫 getData 將返回一個 Promise 例項
複製程式碼
Promise 的原型方法
Promise 一共有三個原型方法,then
, catch
和 finally
。
then
then
方法接受兩個函式引數,一個是成功時候執行,一個是失敗時執行。
而且then
方法將會返回一個新的 Promise 例項,這就代表可以進行鏈式操作。
立即呼叫resolve
的Promise
,它then
方法的引數函式會放到本次事件迴圈末尾。
let p1 = getData('http://www.a.cn')
let onFulfilled = data => console.log(data)
let onRejected = err => console.log(err)
p1.then(onFulfilled, onRejected)
// 當成功時將會呼叫第一個回撥函式,並把 resolve 傳入的引數再全部傳入 onFulfilled 中
// 當成功時將會呼叫第二個回撥函式,並把 resolve 傳入的引數再全部傳入 onRejected 中
let p2 = getData('http://www.a.cn')
p2.then(url => getData(url))
.then(data => console.log(data)) // 鏈式操作
// ------------------
let p = new Promise(resolve => {
console.log(1)
resolve(3)
})
console.log(2)
setTimeout(() => console.log(4))
p.then(num => console.log(num))
// 列印順序是 1 2 3 4
複製程式碼
catch
catch
方法接受一個函式引數onRejected
,catch
其實就是then
的第二個引數。
catch
方法一般放在最後面,前面then
方法,將會冒泡到它這裡。
catch
返回的還是一個 Promise 物件。不過catch
捕獲不了後面的then
方法丟擲的錯誤當然catch
方法中也可以丟擲錯誤。
let p3 = getData('http://a.com')
p3.then(data => console.log(data))
.then(() => throw new Error('error')) // 丟擲錯誤
.then(() => console.log(1))
.catch(err => console.log(err))
// catch 將會捕獲上面的錯誤,而且第三個 then 方法會被跳過
複製程式碼
Promise
中未捕獲的錯誤不會終止指令碼執行而是列印一個未捕獲 promise 錯誤提示。
finally
finally
方法接受一個函式引數onFinally
。它不管 Promise 物件最後狀態如何,都會執行的操作。finally方法的回撥函式不接受任何引數。
它返回一個設定了 finally 回撥函式的Promise物件。
Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};
// finally 相當於返回一個已經帶兩個引數的 then 方法
複製程式碼
Promise 方法
Promise 一共有 4 個靜態方法。分別是all
, race
, resolve
和 reject
。
resolve
resolve
接受一個引數,返回一個狀態由給定value決定的Promise物件。
如果引數是 Promise 物件則直接返回。
如果引數是thenable(即,帶有then方法的物件),then 方法會作為Promise
的引數,立即執行。
如果是其他值返回一個新的 Promise 物件,狀態為resolved,該value傳遞給對應的then方法。
Promise.resolve(1).then(num => {
console.log(num)
});
複製程式碼
reject
reject
方法接受一個引數,返回一個狀態為失敗的Promise物件,並將給定的失敗資訊傳遞給對應的處理方法。
Promise.reject('error');
// 等同於
new Promise((resolve, reject) => reject('error'))
複製程式碼
all
all
方法接受具有 iterable 介面 引數。
這個方法返回一個新的promise物件,該promise物件在iterable引數物件裡所有的promise物件都成功的時候才會觸發成功,一旦有任何一個iterable裡面的promise物件失敗則立即觸發該promise物件的失敗。
這個新的promise物件在觸發成功狀態以後,會把一個包含iterable裡所有promise返回值的陣列作為成功回撥的返回值,順序跟iterable的順序保持一致
如果這個新的promise物件觸發了失敗狀態,它會把iterable裡第一個觸發失敗的promise物件的錯誤資訊作為它的失敗錯誤資訊。
引數中的每個專案都是一個 Promise 物件,如果不是則用 resolve
方法轉換成 Promise 物件。
race
race
方法和 all
方法一樣,但是當iterable
引數裡的任意一個子 Promise 被成功或失敗後,返回的 Promise 物件的狀態就變成這個子 Promise 物件的狀態,它的值或錯誤資訊也會傳遞給返回 Promise 物件的回撥函式。
Promise 的屬性
Promise 一共有兩個屬性,length
和 prototype
。
length屬性,其值總是為 1 (構造器引數的數目)。