Promise 有個缺點就是一旦建立就沒法取消,因此本質上 Promise 是沒法被終止的,但咱們在開發過程當中可能會遇到下面兩個需求:promise
就是在某個 then/catch 執行以後,不想讓後續的鏈式調用繼續執行了,即:網絡
somePromise
.then(() => {})
.then(() => {
// 終止 Promise 鏈,讓下面的 then、catch 和 finally 都不執行
})
.then(() => console.log('then'))
.catch(() => console.log('catch'))
.finally(() => console.log('finally'))
複製代碼
答案就是在 then/catch 的最後一行返回一個永遠 pending 的 promise 便可:app
return new Promise((resolve, reject) => {})
複製代碼
這樣的話後面全部的 then、catch 和 finally 都不會執行了。dom
注意這裏是中斷而不是終止,由於 Promise 沒法終止,這個中斷的意思是:在合適的時候,把 pending 狀態的 promise 給 reject 掉。例如一個常見的應用場景就是但願給網絡請求設置超時時間,一旦超時就就中斷,咱們這裏用定時器模擬一個網絡請求,隨機 3 秒以內返回:函數
const request = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('收到服務端數據')
}, Math.random() * 3000)
})
複製代碼
若是認爲超過 2 秒就是網絡超時,能夠對該 promise 寫一個包裝函數 timeoutWrapper:ui
function timeoutWrapper(p, timeout = 2000) {
const wait = new Promise((resolve, reject) => {
setTimeout(() => {
reject('請求超時')
}, timeout)
})
return Promise.race([p, wait])
}
複製代碼
因而就能夠像下面這樣用了:spa
const req = timeoutWrapper(request)
req.then(res => console.log(res)).catch(e => console.log(e))
複製代碼
不過這種方式並不靈活,由於終止 promise 的緣由可能有不少,例如當用戶點擊某個按鈕或者出現其餘事件時手動終止。因此應該寫一個包裝函數,提供 abort 方法,讓使用者本身決定什麼時候終止:code
function abortWrapper(p1) {
let abort
let p2 = new Promise((resolve, reject) => (abort = reject))
let p = Promise.race([p1, p2])
p.abort = abort
return p
}
複製代碼
使用方法以下:事件
const req = abortWrapper(request)
req.then(res => console.log(res)).catch(e => console.log(e))
setTimeout(() => req.abort('用戶手動終止請求'), 2000) // 這裏能夠是用戶主動點擊
複製代碼
最後,再次強調一下,雖然 promise 被中斷了,可是 promise 並無終止,網絡請求依然可能返回,只不過那時咱們已經不關心請求結果了。開發