Nguyên tắc: song song mặc định, tuần tự khi có ràng buộc.
// Tuần tự: 3 request 200ms => ~600ms
for (const id of ids) {
results.push(await getUser(id))
}
// Song song: ~200ms
const results = await Promise.all(ids.map(getUser))Bắt buộc tuần tự khi:
- Request sau cần kết quả của request trước (lấy token rồi mới gọi API; lấy nextCursor để phân trang).
- Thao tác ghi phải đúng thứ tự (trừ tiền rồi mới tạo đơn).
- Backend hoặc rate limit không chịu nổi burst — khi đó thường nên giới hạn concurrency thay vì tuần tự hoàn toàn.
Nên song song khi các lời gọi độc lập — đây là lỗi hiệu năng hay gặp nhất: await xếp chồng trong cùng một hàm khiến thời gian cộng dồn thay vì lấy max.
Một bẫy cần biết: khi tạo promise trước rồi mới await, chúng đã chạy song song sẵn:
const userP = getUser() // bắt đầu ngay
const ordersP = getOrders() // bắt đầu ngay
const [user, orders] = [await userP, await ordersP]Cách viết này song song nhưng không an toàn về lỗi như Promise.all: nếu ordersP reject trước khi tới lượt await nó, sẽ có unhandled rejection.
Dùng Promise.all cho gọn và an toàn.