Cách thực hiện xử lý bất đồng bộ (asynchronous) trong JavaScript

Xử lý bất đồng bộ (asynchronous) là một khía cạnh quan trọng trong lập trình JavaScript để đảm bảo ứng dụng của bạn có thể xử lý nhiều tác vụ cùng một lúc mà không bị chặn và giữ cho giao diện người dùng (UI) luôn phản hồi. Trong bài viết này, chúng ta sẽ tìm hiểu về cách thực hiện xử lý bất đồng bộ trong JavaScript bằng cách sử dụng các cơ chế như Callback, Promise và Async/Await.

Callback Functions

Callback là một hàm được truyền vào như một tham số cho một hàm khác và được gọi lại sau khi một tác vụ bất đồng bộ hoàn thành. Đây là một cách cổ điển để thực hiện xử lý bất đồng bộ trong JavaScript. Dưới đây là một ví dụ:

function fetchData(callback) {
// Giả định tác vụ bất đồng bộ
setTimeout(() => {
const data = 'Dữ liệu đã được tải';
callback(data);
}, 2000);
}
function processData(data) {
console.log(‘Xử lý dữ liệu:’, data);
}

fetchData(processData);

 

Trong ví dụ trên, fetchData là một hàm chứa tác vụ bất đồng bộ (trong trường hợp này là setTimeout). Khi tác vụ hoàn thành, nó gọi lại hàm processData với dữ liệu đã tải. Điều này cho phép xử lý dữ liệu sau khi nó đã được tải.

Tuy callback functions đơn giản và dễ sử dụng, nhưng khi có nhiều tác vụ bất đồng bộ liên tiếp hoặc lồng nhau, sẽ dễ dẫn đến callback hell, khiến mã trở nên khó đọc và khó bảo trì.

JavaScript Logo Color Scheme » Black » SchemeColor.com

Promise

Promise là một cơ chế được giới thiệu trong ECMAScript 6 (ES6) để xử lý bất đồng bộ một cách dễ dàng và linh hoạt hơn. Promise đại diện cho một giá trị chưa xác định khi một tác vụ bất đồng bộ đang được thực thi và trả về kết quả cuối cùng. Dưới đây là một ví dụ:

function fetchData() {
return new Promise((resolve, reject) => {
// Giả định tác vụ bất đồng bộ
setTimeout(() => {
const data = 'Dữ liệu đã được tải';
resolve(data);
}, 2000);
});
}
fetchData()
.then(data => {
console.log(‘Xử lý dữ liệu:’, data);
})
.catch(error => {
console.error(‘Đã xảy ra lỗi:’, error);
});

 

Trong ví dụ trên, fetchData trả về một Promise. Khi tác vụ hoàn thành thành công, ta gọi resolve với dữ liệu đã tải. Nếu có lỗi xảy ra, ta gọi reject với lỗi tương ứng. Chúng ta có thể sử dụng .then để xử lý kết quả thành công và .catch để xử lý lỗi.

Promise giúp giảm callback hell bằng cách cho phép chúng ta xử lý các tác vụ bất đồng bộ liên tiếp thông qua chuỗi .then. Tuy nhiên, khi có nhiều tác vụ bất đồng bộ, việc lồng nhau các Promise có thể gây ra hiệu ứng pyramid of doom.

10 Best A.I. JavaScript Generator Tools (2023) - HashDork

Async/Await

Async/Await là một cú pháp mới trong JavaScript giúp thực hiện xử lý bất đồng bộ một cách tuần tự và dễ đọc hơn. Nó dựa trên Promise và cho phép viết mã bất đồng bộ theo kiểu tương tự như viết mã đồng bộ. Dưới đây là một ví dụ:

function fetchData() {
return new Promise((resolve, reject) => {
// Giả định tác vụ bất đồng bộ
setTimeout(() => {
const data = 'Dữ liệu đã được tải';
resolve(data);
}, 2000);
});
}
async function processData() {
try {
const data = await fetchData();
console.log(‘Xử lý dữ liệu:’, data);
} catch (error) {
console.error(‘Đã xảy ra lỗi:’, error);
}
}

processData();

 

Trong ví dụ trên, processData được định nghĩa với từ khóa async. Bên trong processData, ta sử dụng await để chờ Promise trả về kết quả. Nếu Promise hoàn thành thành công, await trả về kết quả đó. Nếu Promise bị reject, nó sẽ ném một lỗi và được bắt bởi khối catch.

Async/Await giúp giảm sự phức tạp của việc xử lý bất đồng bộ, làm cho mã trở nên dễ đọc và dễ hiểu hơn. Nó cho phép chúng ta viết mã tương tự như viết mã đồng bộ, mà không cần lồng nhau các callback hoặc Promise.

Adobe Taps Polygon to Scale NFT Functionality in Behance Social Platform - Decrypt

Đó là cách thực hiện xử lý bất đồng bộ trong JavaScript bằng cách sử dụng callback, Promise và Async/Await. Mỗi cơ chế có ưu điểm và cách sử dụng riêng, tùy thuộc vào tình huống và sự lựa chọn của bạn. Tuy nhiên, Async/Await thường được coi là cách tiện lợi và dễ đọc nhất hiện nay.