ES6 提供的 Promise 方法和 ES7 提供的 Async/Await 語法糖都可以更好解決多層回調問題, 詳細用法可參考:https://www.cnblogs.com/cckui/p/9915604.html,下面進一步介紹 promise 和 async/await 用法的異同。
首先定義以下三個異步函數:
function sleep3000() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('sleep3000 執行完成');
resolve(new Date());
}, 3000);
})
};
function sleep2000() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('sleep2000 執行完成');
resolve(new Date());
}, 2000);
})
};
function sleep4000() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('sleep4000 執行完成');
resolve(new Date());
}, 4000);
})
};
1. 使用 promise 方法分別執行以上三個函數
console.log('Now:', new Date());
sleep3000().then((d) => {
console.log('3000:', d);
})
sleep2000().then((d) => {
console.log('2000:',d);
})
sleep4000().then((d) => {
console.log('2000:',d);
})
最終打印結果:
Now: 2019-04-08T02:29:38.388Z
sleep2000 執行完成
2000: 2019-04-08T02:29:40.398Z
sleep3000 執行完成
3000: 2019-04-08T02:29:41.398Z
sleep4000 執行完成
2000: 2019-04-08T02:29:42.394Z
2. 使用 promise.all()
方法
Promise 的 all() 方法提供了並行執行異步操作的能力,即在所有異步操作執行完后才執行回調, all()里面接收一個數組,數組中每個元素都返回一個 promise 對象。
all()里面的異步都執行完成后,才會把每個異步結果以數組的形式放入 then 中。
某些情況下,如果上面sleep3000、sleep200、sleep4000分別代表頁面不同模塊的加載時間,在頁面剛打開時,需要當所有模塊加載完成后,清除loading。此時可以作如下處理:
console.log('Now:', new Date());
Promise.all([
sleep2000(),
sleep3000(),
sleep4000()
]).then((res) => {
console.log(res)
})
最終打印結果:
Now: 2019-04-08T02:43:07.139Z
sleep2000 執行完成
sleep3000 執行完成
sleep4000 執行完成
[ 2019-04-08T02:43:09.144Z,
2019-04-08T02:43:10.145Z,
2019-04-08T02:43:11.144Z ]
3. 使用 promise.race()
方法
Promise 的 race() 方法 與 all () 相反,即只以執行最快的那個promise為准,一旦race()中的某個promise解決或拒絕,所有返回的 promise就會解決或拒絕。
console.log('Now:', new Date());
Promise.race([
sleep2000(),
sleep3000(),
sleep4000()
]).then((res) => {
console.log(res)
})
因為 sleep2000 最先執行完成,所以在2秒后,就會立即進入then。
最終打印結果:
Now: 2019-04-08T02:44:34.193Z
sleep2000 執行完成
2019-04-08T02:44:36.200Z
sleep3000 執行完成
sleep4000 執行完成
注意:2秒進入 then 后, sleep3000 和 sleep4000 並沒有被停止, 仍會繼續走完,只是不會處理resolve或reject。
4. async/await 處理以上三個函數
console.log('Now:', new Date());
async function getDate () {
let res1 = await sleep3000();
let res2 = await sleep2000();
let res3 = await sleep4000();
console.log('3000:', res1);
console.log('2000:', res2);
console.log('4000:', res3);
}
getDate();
最終打印結果:
Now: 2019-04-08T02:58:23.990Z
sleep3000 執行完成
sleep2000 執行完成
sleep4000 執行完成
3000: 2019-04-08T02:58:26.996Z
2000: 2019-04-08T02:58:29.001Z
4000: 2019-04-08T02:58:33.004Z
通過打印時間,可見,每處理完前一個await,才會處理下一個await,上面所有處理完花費了9秒。
所以, 只有當處理后面await需要前一個await返回值時,才可以用以上方法。
5. async/await 中使用 promise.all 並行處理異步操作
當三個異步相互之間沒有關系,需要同時發送時:
console.log('Now:', new Date());
async function getdate () {
let res1 = sleep3000();
let res2 = sleep2000();
let res3 = sleep4000();
let res = await Promise.all([res1, res2, res3]);
console.log(res);
}
getdate();
最終打印結果:
sleep2000 執行完成
sleep3000 執行完成
sleep4000 執行完成
[ 2019-04-08T03:11:24.280Z,
2019-04-08T03:11:23.280Z,
2019-04-08T03:11:25.275Z ]
注意:
對比 2 和 5 的打印結果,可以看出,二者打印的返回數組里面的順序是有區別的:
- 只用promise.all()時,各個異步是無序的;
- 在 async/await 中使用 promise.all(), 各個異步是有序的。