竟態,意思是程序的運行結果與時間有關,可能前一秒是 A 結果但是推遲幾秒後是 B 結果。
什麼時候用到竟態
當我們需要判斷異步方法執行順序或時間的時候:
function delay(time = 1000) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject("超時");
}, time);
});
}
Promise.race([test(), delay(3000)]).then(
() => {
// test()及時完成
},
error => {
// foo產生錯誤或者沒有在3秒之內完成
}
);
// 同理於
// Promise.race([test(), delay(3000)]).then(
// () => {
// // test()及時完成
// }).catch(
// error => {
// // foo產生錯誤或者沒有在3秒之內完成
// }
// );
先分析一下上面代碼:我們創建了一個 delay
函數,這個函數返回一個 promise
,promise
設置定時 time
時間執行 reject。promise 如果不給他返回 resolve
或者 reject
狀態那麼他將一直處於 pending
狀態。promise
的 race 方法接收一個數組作爲參數,返回最先執行完的那個參數方法,如果該方法爲 resolve
就返回 resolve
如果是 reject
就返回 reject
。
在上述例子中,race
的參數數組有 test
和 delay
,如果 test
在 3 秒之內完成了並且 test
方法裏沒有 reject
操作,那麼就會走到 then
第一個方法;如果 test 執行出了錯誤(使用 reject
拋出錯誤)或者沒有在 3 秒之內完成,那麼 3 秒後就會執行 delay 函數,走 then
第二個方法,也就是 catch
操作,而 delay 函數此時就會 reject
返回’超時’值。
實際應用
在實際應用中我們可以預先判斷一個接口的超時操作,超過多長時間就認定爲超時:
function delay(time = 1000) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject("請求超時");
}, time);
});
}
let p = Promise.race([fetch("/api/.."), delay(3000)]);
p.then(res => {
console.log(res);
});
p.catch(error => {
console.error(error);
});
另外,我們也可以藉助 async 在其他場景使用:
function delay(time = 1000) {
return new Promise((resolve, reject) => {
setTimeout(resolve, time);
});
}
async function foo() {
// fetch data 結束後等待一段時間再進行某項操作
await delay(2000);
// do something...
}
比如在生產中我們需要在請求完接口成功後,提示成功彈層 1s 再跳轉界面。我們不知道請求需要花費多長時間,但是我們能知道請求何時完成,當請求完成的時候開始計時,到了時間後再去進行我們需要的操作。
delay
方法返回一個 promise,裏面使用 setTimeout
定時改變 promise 狀態爲 resolve,所以就能做到 2000 毫秒後得到 resolve
狀態,再執行後續代碼。上面我們講過如果 promise 不返回任何狀態的話它會處於 pending
狀態阻塞後續代碼執行。
我們來看一個有趣的例子:
async function foo() {
await new Promise(() => {});
console.log("1");
}
foo();
async/await 和 promise 一樣,async 會返回一個 promise,await
會等待 promise 執行。當 Promise 沒有狀態返回的時候,console.log("1");
不執行。當我們返回 resolve/reject:
async function foo() {
await new Promise(resolve => resolve(2));
console.log("1");
}
foo();
這時會打印出“1”,既然能夠控制它返回成功或者失敗狀態,就可以在返回狀態時進行時間控制。
爲什麼不直接用 setTimeout,因爲 setTimeout 無法判斷異步結果是成功還是失敗。