Promise là một giải pháp không thể thiếu khi xử lý bất đồng bộ trong JavaScript, đặc biệt phổ biến trong phát triển frontend. Hiểu rõ cách dùng và nguyên lý hoạt động của Promise giúp bạn tránh được "callback hell" và viết code sạch hơn.
Promise là gì?
Promise đại diện cho một giá trị có thể chưa sẵn sàng ngay lập tức, nhưng sẽ được hoàn thành (hoặc thất bại) trong tương lai. Nó có ba trạng thái:
- pending: đang chờ xử lý
- fulfilled: đã hoàn thành thành công
- rejected: đã bị từ chối do lỗi
Một khi chuyển sang trạng thái fulfilled hoặc rejected, Promise không thể thay đổi lại — điều này đảm bảo tính nhất quán trong xử lý kết quả.
Sử dụng cơ bản
Tạo một Promise bằng cách gọi constructor với một hàm executor nhận hai tham số: resolve và reject.
const task = new Promise((complete, fail) => {
setTimeout(() => {
const outcome = Math.random() > 0.5 ? 'OK' : null;
outcome ? complete(outcome) : fail('Lỗi rồi!');
}, 1500);
});
Phương thức .then()
Dùng để xử lý kết quả thành công hoặc thất bại:
task.then(
result => console.log('Thành công:', result),
error => console.log('Thất bại:', error)
);
Phương thức .catch()
Xử lý lỗi tập trung, kể cả lỗi xảy ra trong callback thành công:
task.then(result => {
console.log('Xong:', result);
undefinedFunction(); // Gây lỗi
}).catch(err => {
console.log('Bắt lỗi:', err.message);
});
Phương thức .finally()
Luôn chạy dù Promise thành công hay thất bại — hữu ích để dọn dẹp tài nguyên:
let loading = true;
function fetchData() {
return new Promise((done, error) => {
setTimeout(() => done("Dữ liệu nhận được"), 800);
});
}
fetchData()
.then(data => console.log(data))
.catch(err => console.error(err))
.finally(() => {
loading = false;
console.log("Đã tắt loading");
});
Các phương thức tiện ích tĩnh
Promise.resolve(value)
Tạo Promise đã hoàn thành ngay lập tức:
Promise.resolve("Xin chào")
.then(msg => console.log(msg)); // "Xin chào"
Promise.reject(reason)
Tạo Promise đã bị từ chối:
Promise.reject(new Error("Có lỗi"))
.catch(e => console.error(e.message));
Promise.all(iterable)
Chờ tất cả Promise hoàn thành. Nếu một Promise thất bại → toàn bộ thất bại:
const tasks = [
Promise.resolve("A"),
Promise.resolve("B"),
Promise.resolve("C")
];
Promise.all(tasks).then(results => {
console.log(results); // ["A", "B", "C"]
});
Promise.allSettled(iterable)
Chờ tất cả Promise hoàn thành hoặc thất bại, trả về mảng kết quả chi tiết:
const mixed = [
Promise.resolve(1),
Promise.reject("lỗi"),
Promise.resolve(3)
];
Promise.allSettled(mixed).then(results => {
results.forEach(r => console.log(r.status));
});
// "fulfilled"
// "rejected"
// "fulfilled"
Promise.any(iterable)
Trả về Promise đầu tiên hoàn thành thành công. Nếu tất cả thất bại → AggregateError:
const fast = new Promise(r => setTimeout(r, 100, "nhanh"));
const slow = new Promise(r => setTimeout(r, 500, "chậm"));
Promise.any([fast, slow]).then(v => console.log(v)); // "nhanh"
Promise.race(iterable)
Trả về kết quả của Promise đầu tiên hoàn thành (thành công hoặc thất bại):
function fetchWithTimeout(url, ms) {
const request = fetch(url);
const timeout = new Promise((_, reject) =>
setTimeout(() => reject("Hết giờ!"), ms)
);
return Promise.race([request, timeout]);
}
Triển khai Promise từ đầu
Dưới đây là cách xây dựng một Promise đơn giản hỗ trợ then chaining và xử lý bất đồng bộ:
const WAITING = 'waiting';
const DONE = 'done';
const FAILED = 'failed';
class SimplePromise {
status = WAITING;
result = undefined;
error = undefined;
successHandlers = [];
failureHandlers = [];
constructor(executor) {
const finish = value => {
if (this.status !== WAITING) return;
this.status = DONE;
this.result = value;
this.successHandlers.forEach(fn => fn());
};
const abort = reason => {
if (this.status !== WAITING) return;
this.status = FAILED;
this.error = reason;
this.failureHandlers.forEach(fn => fn());
};
try {
executor(finish, abort);
} catch (e) {
abort(e);
}
}
then(onSuccess, onFailure) {
return new SimplePromise((nextResolve, nextReject) => {
const handleSuccess = () => {
try {
const output = onSuccess ? onSuccess(this.result) : this.result;
resolveNext(output, nextResolve, nextReject);
} catch (e) {
nextReject(e);
}
};
const handleFailure = () => {
if (onFailure) {
try {
const output = onFailure(this.error);
resolveNext(output, nextResolve, nextReject);
} catch (e) {
nextReject(e);
}
} else {
nextReject(this.error);
}
};
if (this.status === DONE) {
setTimeout(handleSuccess, 0);
} else if (this.status === FAILED) {
setTimeout(handleFailure, 0);
} else {
this.successHandlers.push(() => setTimeout(handleSuccess, 0));
this.failureHandlers.push(() => setTimeout(handleFailure, 0));
}
});
}
catch(onFailure) {
return this.then(null, onFailure);
}
}
function resolveNext(value, resolve, reject) {
if (value instanceof SimplePromise) {
value.then(resolve, reject);
} else {
resolve(value);
}
}
Đoạn code trên hỗ trợ:
- Thực thi đồng bộ và bất đồng bộ
- Chaining liên tiếp các
.then() - Xử lý Promise lồng nhau
- Bắt lỗi với
.catch() - Không block luồng chính nhờ
setTimeout(..., 0)