So sánh Closure và Promise trong JavaScript: Điểm mạnh, yếu và tình huống sử dụng
Bài viết này so sánh điểm mạnh, yếu và tình huống sử dụng của Closure và Promise trong JavaScript, giúp bạn hiểu và lựa chọn giải pháp phù hợp cho dự án của mình.
imdevquen
Jun 1, 2026 · 6 min read
Định nghĩa Closure và Promise
Trong JavaScript, Closure là một hàm có khả năng "nhớ" các biến từ scope bên ngoài ngay cả khi hàm đó đang chạy ở một scope khác. Điều này có nghĩa là Closure cho phép truy cập các biến bên ngoài hàm mà không cần phải truyền các biến này vào như tham số. Khi mình thử làm việc với Closure, tôi đã thấy nó thực sự hữu ích khi cần duy trì trạng thái của một biến theo cách mà cách truyền tham số thông thường không thể thực hiện được.
function counter() {
let count = 0;
return function() {
count++;
return count;
};
}
const increment = counter(); // Tạo một closure
console.log(increment()); // In ra 1
console.log(increment()); // In ra 2
Promise trong JavaScript là một đối tượng đại diện cho một giá trị có thể có trong tương lai. Đặc điểm nổi bật của Promise là nó có ba trạng thái: pending (đang chờ), fulfilled (thực hiện thành công), và rejected (thực hiện không thành công). Đối với tôi, việc sử dụng Promise làm cho code của tôi trở nên rõ ràng hơn, đặc biệt là khi xử lý các tác vụ bất đồng bộ.
fetch('/api')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
Cách hoạt động của Closure và Promise
Closure hoạt động dưới cơ chế giữ lại một ngữ cảnh, tức là khi một hàm được định nghĩa bên trong một hàm khác, hàm bên trong này có thể truy cập đến các biến của hàm lồng bên ngoài. Điều này tạo ra một môi trường thuận lợi cho việc duy trì trạng thái của biến trong quá trình thực thi. Theo kinh nghiệm của mình, khi cần phải sử dụng lại một giá trị giữa nhiều lần gọi hàm, Closure là một công cụ cực kỳ mạnh mẽ. Kết quả là bạn có thể lưu trữ trạng thái mà không cần dùng đến các biến toàn cục, điều này giúp mã của bạn gọn gàng và dễ quản lý hơn.
Ví dụ, hãy xem đoạn code sau. Mỗi khi chúng ta gọi hàm increment, nó sẽ cộng giá trị của count lên 1 và trả về kết quả. Mặc dù hàm counter đã thực hiện xong, count vẫn tồn tại trong bộ nhớ nhờ Closure. Điều này là một minh chứng tuyệt vời cho sức mạnh của Closure trong JavaScript.
Ngược lại, Promise làm việc với các thao tác bất đồng bộ. Khi khởi tạo một Promise, chúng ta xác định rằng khi một tác vụ nào đó hoàn thành (hoặc thất bại), nó sẽ kích hoạt một trong hai callback tương ứng với trạng thái của nó. Điều này không những giúp cải thiện độ sạch và khả năng bảo trì của mã nguồn mà còn giúp bạn tránh khỏi tình trạng "callback hell" nổi tiếng.
Các tình huống sử dụng cho Closure và Promise
Closure thường được sử dụng trong các tình huống cần duy trì trạng thái giữa các lần gọi hàm. Một ví dụ điển hình là việc tạo ra các hàm điều khiển thông qua closures. Khi mình bắt đầu học JavaScript, tôi thấy ví dụ sau thực sự dễ dàng để hiểu sự hoạt động của Closure.
function makeCounter() {
let count = 0;
return {
increment: function() { return ++count; },
getCount: function() { return count; },
};
}
const counter = makeCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
Trong ví dụ trên, mỗi lần gọi hàm increment, giá trị của biến count sẽ được gia tăng, và chúng ta có thể dễ dàng lấy giá trị hiện tại mà không gặp phải bất kỳ trở ngại nào. Điều này cho thấy cách mà Closure giúp duy trì trạng thái một cách hiệu quả.
Còn đối với Promise, chúng thường được sử dụng trong các tình huống hết sức thiết thực khi cần thực hiện các tác vụ bất đồng bộ như truy vấn API hoặc xử lý các tác vụ file I/O. Rõ ràng, công cụ này cho phép lập trình viên quản lý các tác vụ này một cách dễ dàng hơn và cải thiện tính bền vững của mã nguồn. Dưới đây là một ví dụ về một hàm sử dụng Promise để lấy dữ liệu từ một API:
function fetchData(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => resolve(data))
.catch(error => reject(error));
});
}
Trong trường hợp này, Promise cho phép chúng ta xử lý thành công hoặc thất bại khi lấy dữ liệu từ một hệ thống bên ngoài một cách thi vị.
Điểm mạnh và điểm yếu của Closure và Promise
| Tiêu chí | Closure | Promise |
|---|---|---|
| Duy trì trạng thái | Có khả năng duy trì trạng thái giữa các lần gọi hàm | Không có khả năng duy trì trạng thái |
| Quản lý bất đồng bộ | Không sử dụng cho các tác vụ bất đồng bộ | Quản lý tốt các tác vụ bất đồng bộ, loại bỏ callback hell |
| Đơn giản hóa mã nguồn | Có thể tạo ra mã nguồn phức tạp hơn nếu không sử dụng đúng cách | Giúp mã nguồn dễ đọc hơn khi xử lý bất đồng bộ |
| Hiệu suất | Có thể tạo ra rò rỉ bộ nhớ nếu không được sử dụng đúng cách | Hiệu suất tốt hơn trong các thao tác bất đồng bộ |
Kết luận: Nên sử dụng Closure hay Promise
Việc lựa chọn giữa Closure và Promise thực sự phụ thuộc vào từng tình huống cụ thể trong dự án phát triển của bạn. Nếu bạn cần duy trì trạng thái giữa các lần gọi hàm hoặc tạo ra các hàm điều khiển phức tạp, Closure là sự lựa chọn hợp lý. Ngược lại, nếu bạn đang xử lý các tác vụ bất đồng bộ và muốn quản lý chúng một cách hiệu quả, bạn nên sử dụng Promise.
Cuối cùng, với cách tiếp cận đúng, bạn có thể linh hoạt kết hợp cả hai kỹ thuật này để phát triển ứng dụng JavaScript của mình một cách hiệu quả hơn. Hãy nhớ rằng khả năng hiểu rõ khi nào nên sử dụng từng công cụ sẽ giúp bạn phát triển mã nguồn tốt hơn và dễ dàng hơn trong quản lý dự án của mình.
Thêm nữa, nếu bạn muốn tìm hiểu thêm về các kỹ thuật tiên tiến hơn trong JavaScript, hãy tham khảo thêm các tình huống sử dụng JavaScript thực tế. Điều này sẽ giúp bạn mở rộng hiểu biết và kỹ năng lập trình của bạn trong lĩnh vực này.