Dùng async/await để giải quyết callback hell — code đọc như synchronous, try/catch natural; Promise.all() cho parallel thay vì await trong for loop.
- Callback hell (pyramid of doom) — ví dụ thực:
fs.readFile('a.txt', (err, data) => { if(err) throw err; db.query(data, (err, rows) => { if(err) throw err; sendEmail(rows[0], (err) => { if(err) throw err; console.log('done') }) }) })— 3 cấp lồng nhau, error handling lặp lại, logic khó theo dõi. - Giải pháp Promise chaining:
readFile('a.txt').then(data => db.query(data)).then(rows => sendEmail(rows[0])).catch(err => console.error(err))— flat hơn nhưng còn awkward với multi-value. - Giải pháp async/await:
try { const data = await readFile('a.txt'); const rows = await db.query(data); await sendEmail(rows[0]); } catch(err) { console.error(err); }— đọc như synchronous code, try/catch natural. - Error propagation khác nhau: callback phải check
errmỗi cấp thủ công, một missed check = silent failure; Promise/async throw tự động bubble up đến .catch/try-catch.
Pitfall async/await: await trong vòng lặp for...of sẽ chạy sequential — dùng Promise.all(items.map(item => process(item))) để parallel.