昨天我們提了JS在非同步的執行流程,學了Call Stack、Callback Queue、Event Loop在執行時扮演的角色
接下來我們要更聚焦在這些非同步的工作,看看它們在程式碼中會長什麼樣子,以及如何從早期的 callback hell 一路演化到現在的 async/await
setTimeout(() => {
console.log('A'); // A:1秒後執行
setTimeout(() => {
console.log('B'); // B:在A完成後,再過1秒執行
setTimeout(() => {
console.log('C'); // C:在B完成後,再過1秒執行
// 如果還有任務D、E、F...
// 就會一直向右延伸下去
}, 1000);
}, 1000);
}, 1000);
// 這個形狀 > 就是「毀滅金字塔」
.then()
) 的方式來組織程式碼.catch()
來集中處理錯誤const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms));
wait(1000)
.then(() => {
console.log('A');
return wait(1000); // 返回一個新的 Promise
})
.then(() => {
console.log('B');
return wait(1000);
})
.then(() => {
console.log('C');
})
.catch(err => {
// 任何一個環節出錯,都會被這裡捕捉到
console.error('發生錯誤:', err);
});
(目前主流的最佳實踐)
async/await
是建立在 Promise 之上的「語法糖」(Syntactic Sugar),它讓你可以用看起來像同步程式碼的方式來編寫非同步程式碼
const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms));
async function runTasks() {
try {
await wait(1000);
console.log('A');
await wait(1000);
console.log('B');
await wait(1000);
console.log('C');
} catch (err) {
// 同樣可以用 try...catch 來處理所有錯誤
console.error('發生錯誤:', err);
}
}
runTasks();
另外還有一些很常出現的Promise.all()
、Promise.race()
Promise.all()
可以同時啟動多個 Promise,等全部完成後才進到then()
,如果中途有一個失敗,就直接進catch()
看一下他的語法怎麼寫:
const wait = (ms, label) =>
new Promise(resolve => setTimeout(() => {
console.log(label);
resolve(label);
}, ms));
Promise.all([
wait(1000, 'A'),
wait(2000, 'B'),
wait(1500, 'C')
]).then(results => {
console.log('All Done:', results);
}).catch(err => {
console.error('A Task Failed:', err);
});
Promise.race()
也是同時啟動多個 Promise,但只取第一個完成或失敗的結果
看一下語法怎麼寫
Promise.race([
wait(1000, 'A'),
wait(2000, 'B'),
wait(1500, 'C')
]).then(result => {
console.log('The First One Done:', result);
}).catch(err => {
console.error('The First One Failed:', err);
});
https://ithelp.ithome.com.tw/articles/10209328
https://ithelp.ithome.com.tw/m/articles/10297362