ใช้ประโยชน์จาก event loop, ทำให้ promise ของคุณทำงานคู่ขนานอย่างถูกต้อง และทำให้การจัดการข้อผิดพลาดแบบอะซิงโครนัสเชื่อถือได้
เปิดบทเรียนนี้ใน Kodokonโมเดลการทำงานอาศัยคิว macrotask (setTimeout, I/O) และคิว microtask (.then, await, queueMicrotask) หลังจากแต่ละงาน เอนจินจะระบายคิว microtask ให้หมด ก่อนจะไปทำงานต่อ ผลที่ตามมาโดยตรง: promise ที่ resolve แล้วจะทำงานก่อน setTimeout(fn, 0) เสมอ และเชนของ microtask ที่ยาวเกินไปก็สามารถทำให้การเรนเดอร์ค้างได้แน่นอนพอ ๆ กับลูปแบบซิงโครนัส
console.log("start");
setTimeout(() => console.log("macrotask"), 0);
Promise.resolve().then(() => console.log("microtask"));
console.log("end");
// start, end, microtask, macrotaskasync/await คือน้ำตาลเคลือบ (syntactic sugar) ที่อยู่บน promise แต่มันซ่อนกับดักด้านประสิทธิภาพไว้: await แต่ละตัวภายในลูปจะ ทำให้การทำงานเป็นลำดับ หากคำร้องขอเป็นอิสระต่อกัน จงเริ่มมันทั้งหมดก่อน แล้วค่อยรอทั้งชุดด้วย Promise.all สำหรับคำร้องขอ 100 มิลลิวินาทีสามรายการ เวอร์ชันแบบลำดับใช้เวลา 300 มิลลิวินาที ส่วนเวอร์ชันคู่ขนานใช้ 100 มิลลิวินาที
const fetchUser = (id) => new Promise((res) => {
setTimeout(() => res({ id }), 100);
});
async function loadSequential(ids) {
const users = [];
for (const id of ids) {
users.push(await fetchUser(id)); // ~100 ms each
}
return users;
}
async function loadParallel(ids) {
return Promise.all(ids.map(fetchUser)); // ~100 ms total
}จงเลือกตัวรวม (combinator) ที่ถูกต้องตามสัญญาความล้มเหลวที่คุณต้องการ: Promise.all reject เมื่อล้มเหลว ครั้งแรก (ทั้งหมดหรือไม่มีเลย), allSettled รอทุกตัวและอธิบายผลลัพธ์แต่ละอัน, race เอาการเสร็จสิ้นครั้งแรก (สำเร็จหรือล้มเหลว มีประโยชน์สำหรับ timeout), any เอาความสำเร็จครั้งแรกและจะ reject ก็ต่อเมื่อทุกอย่างล้มเหลวเท่านั้น สำหรับแดชบอร์ดที่ต้องแสดงผลลัพธ์บางส่วน allSettled มักเป็นตัวเลือกที่ถูกต้องเสมอ
const tasks = [
Promise.resolve("profile loaded"),
Promise.reject(new Error("network unavailable")),
];
const results = await Promise.allSettled(tasks);
for (const r of results) {
if (r.status === "fulfilled") {
console.log("success:", r.value);
} else {
console.error("failure:", r.reason.message);
}
}console.log แบบซิงโครนัส, คอลแบ็ก Promise.resolve().then, และคอลแบ็ก setTimeout(fn, 0) ทำงานตามลำดับใด?try { doAsync(); } catch (e) {} ที่ไม่มี await จึงจับการ reject จาก doAsync ไม่ได้?