Promise đã resolve phương án dự phòng nhưng đoạn xử lý chính vẫn chạy tiếp. resolve điều khiển kết quả Promise; nó không phải câu lệnh thoát hàm. Khi bọc API callback hoặc viết nhánh kết thúc sớm, cần tách hai trách nhiệm này.
Các ví dụ chạy trong async function hoặc môi trường hỗ trợ top-level await. Chúng dùng dữ liệu trong bộ nhớ, không gọi mạng và không cần timer.
1. Executor chạy ngay khi tạo Promise
const events = [];
const task = new Promise(resolve => {
events.push('executor');
resolve('ready');
});
events.push('after constructor');
console.log(events.join(',')); // executor,after constructor
console.log(await task); // ready
new Promise gọi executor đồng bộ trong quá trình khởi tạo. Bọc tính toán nặng trong executor không tự chuyển nó sang luồng nền. Việc đợi kết quả bằng await và thời điểm thân executor bắt đầu là hai vấn đề khác nhau.
2. Mã phía sau resolve vẫn có thể chạy
const events = [];
const task = new Promise((resolve, reject) => {
resolve('ready');
events.push('still running');
reject(new Error('too late'));
});
console.log(await task); // ready
console.log(events.join(',')); // still running
Việc ghi events vẫn xảy ra. Lời reject sau đó không đổi được kết quả đã chốt, nhưng điều này không ngăn những tác dụng phụ khác tiếp tục diễn ra. Không dùng tính chất chỉ nhận kết quả đầu tiên như một cơ chế tránh ghi dữ liệu hai lần.
3. Muốn dừng nhánh, dùng return rõ ràng
async function choose(valid) {
const events = [];
const result = await new Promise(resolve => {
if (!valid) {
resolve('fallback');
return;
}
events.push('work');
resolve('ready');
});
return result + ':' + events.length;
}
console.log(await choose(false)); // fallback:0
console.log(await choose(true)); // ready:1
return thoát executor trong nhánh không hợp lệ, còn resolve cung cấp kết quả. Giá trị return của executor bị bỏ qua, nên chỉ viết return 'fallback' không làm Promise fulfilled. Trong callback lồng, return cũng chỉ thoát callback đó, không tự thoát toàn bộ hàm ngoài.
choose dùng constructor để minh họa luồng điều khiển, không phải mẫu bắt buộc cho một phép chọn đơn giản. Nếu chỉ có dữ liệu đồng bộ, viết nhánh if trực tiếp; nếu dependency đã trả Promise, thường có thể return hoặc await nó thay vì bọc thêm constructor.
4. resolve bằng một Promise khác chưa chắc hoàn tất ngay
let release;
const inner = new Promise(resolve => { release = resolve; });
const outer = new Promise(resolve => {
resolve(inner);
resolve('ignored');
});
release('inner result');
console.log(await outer); // inner result
Lần resolve đầu khóa outer vào kết quả của inner. Lần resolve sau không thay thế nó, dù inner lúc đó chưa fulfilled. Ví dụ tự kiểm chứng rằng “đã gọi resolve” không đồng nghĩa đã có giá trị thành công cuối cùng.
Nếu inner reject, outer cũng nhận kết quả từ chối đó. Đây là theo dõi kết quả, không phải cơ chế hủy các công việc đã khởi chạy. Quyền sở hữu và cleanup của tác vụ cần thiết kế riêng.
5. Review điểm kết thúc và tác dụng phụ
- Nhánh resolve hoặc reject có cần thoát bằng return không?
- Callback có thể được gọi nhiều lần và lặp công việc bên ngoài không?
- Executor có tính toán đồng bộ nặng không?
- Promise đang theo kết quả Promise khác hay đã fulfilled?
- Test có kiểm tra tác dụng phụ sau khi kết quả đã chốt không?
Tám khối ví dụ Việt–Anh đã chạy tuần tự bằng Node.js, kèm kiểm tra kết quả đầu tiên và Promise con reject. Chưa kiểm thử API callback thực tế hoặc hiệu năng. Tham khảo MDN Promise constructor và MDN Promise.




Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.