Async/Await Là Gì? Async/Await Trong Javascript Được Ứng Dụng Như Thế Nào
13/05/2025 06:47
Bài viết này sẽ đi sâu vào giải mã Async await là gì, cách chúng hoạt động và minh họa bằng các ví dụ thực tế
Trong thế giới phát triển web hiện đại, JavaScript là ngôn ngữ không thể thiếu, và việc xử lý các tác vụ bất đồng bộ (asynchronous operations) là một phần cốt lõi của lập trình JavaScript. Từ việc gọi API để lấy dữ liệu, đọc nội dung tệp, đến thiết lập các bộ hẹn giờ, các thao tác này thường không hoàn thành ngay lập tức. Theo thời gian, JavaScript đã phát triển các cách khác nhau để xử lý tính bất đồng bộ này, từ callback truyền thống, Promises, và gần đây nhất là async/await. Vậy, Async await là gì? Tại sao async/await lại trở nên phổ biến và chúng được ứng dụng như thế nào trong Javascript? Bài viết này sẽ đi sâu vào giải mã Async await là gì, cách chúng hoạt động và minh họa bằng các ví dụ thực tế.
1. Async Await Là Gì? Định Nghĩa và Mục Đích
Để hiểu rõ về Async await là gì, chúng ta cần biết rằng chúng là các từ khóa được giới thiệu trong ECMAScript 2017 (ES8) nhằm đơn giản hóa việc viết và làm việc với các tác vụ bất đồng bộ dựa trên Promises. Về cơ bản, async và await là "đường cú pháp" (syntactic sugar) cho Promises, giúp mã bất đồng bộ trông và hoạt động giống như mã đồng bộ hơn, từ đó dễ đọc, dễ viết và dễ hiểu hơn.
Mục đích chính của Async await là gì là giải quyết những hạn chế và sự phức tạp thường gặp khi sử dụng callback lồng nhau (callback hell) hoặc các chuỗi Promises dài dòng, khó đọc. async/await cho phép bạn viết mã bất đồng bộ theo một luồng tuần tự hơn, làm giảm gánh nặng nhận thức khi xử lý các tác vụ không đồng bộ.
- Từ khóa async: Đặt trước một khai báo hàm (function declaration, arrow function, method trong object/class) để chỉ ra rằng hàm đó sẽ luôn trả về một Promise.
- Từ khóa await: Chỉ có thể được sử dụng bên trong một hàm được đánh dấu là async. Nó tạm dừng việc thực thi của hàm async cho đến khi một Promise mà nó đang chờ được "giải quyết" (resolved hoặc rejected).
Khi bạn sử dụng await trước một Promise, async function sẽ dừng lại tại dòng đó cho đến khi Promise hoàn thành. Nếu Promise thành công (resolved), await sẽ trả về giá trị mà Promise đó đã giải quyết. Nếu Promise thất bại (rejected), await sẽ ném ra một lỗi, có thể được bắt bằng khối try...catch.
2. Async Await Hoạt Động Như Thế Nào? Mối Liên Hệ Với Promises
Như đã đề cập, Async await là gì được xây dựng trên nền tảng của Promises. Chúng không thay thế Promises mà chỉ cung cấp một cú pháp thuận tiện hơn để làm việc với chúng.
Một hàm được đánh dấu là async sẽ luôn trả về một Promise. Nếu hàm trả về một giá trị thông thường (không phải Promise), JavaScript sẽ tự động bọc giá trị đó trong một Promise đã resolved. Nếu hàm ném ra một ngoại lệ (error), Promise được trả về sẽ ở trạng thái rejected.
Từ khóa await chỉ hoạt động bên trong các hàm async. Khi bạn đặt await trước một Promise, việc thực thi của hàm async sẽ "tạm dừng" (non-blocking, nghĩa là không chặn toàn bộ luồng chính) cho đến khi Promise đó kết thúc.
- Nếu Promise được giải quyết (resolved) thành công, await sẽ "giải nén" giá trị từ Promise và bạn có thể sử dụng giá trị đó ngay lập tức ở dòng tiếp theo.
- Nếu Promise bị từ chối (rejected) do lỗi, await sẽ ném ra lỗi đó. Bạn cần sử dụng khối try...catch để bắt lỗi này, tương đương với việc sử dụng .catch() trong Promises.
Ví dụ, xem xét một hàm trả về Promise sau:
Sử dụng Promises với .then():
Sử dụng async/await:
Rõ ràng, cú pháp với async/await trông gọn gàng và dễ đọc hơn, giống với cách chúng ta viết mã đồng bộ.
3. Cách Sử Dụng Async Await Trong Javascript
Để sử dụng Async await là gì một cách hiệu quả, bạn cần nắm vững cách áp dụng các từ khóa này trong mã của mình:
3.1. Khai Báo Hàm async
Bạn có thể khai báo một hàm async bằng nhiều cách:
Khai báo hàm thông thường:
Hàm mũi tên (Arrow Function):
Phương thức trong object/class:
3.2. Sử Dụng await Bên Trong Hàm async
Điều quan trọng cần nhớ là từ khóa await chỉ có thể được sử dụng bên trong các hàm được đánh dấu là async. Nếu bạn cố gắng sử dụng await bên ngoài một hàm async (ví dụ: ở cấp độ gốc của module), bạn sẽ gặp lỗi cú pháp.
3.3. Xử Lý Lỗi Với try...catch
Như đã đề cập, khi một Promise bị từ chối sau khi bạn sử dụng await, nó sẽ ném ra một lỗi. Cách sử dụng hàm boolean trong java khi làm việc với lỗi bất đồng bộ trong Javascript là sử dụng khối try...catch.
3.4. Chờ Nhiều Promise Cùng Lúc
Nếu bạn cần chờ nhiều Promises hoàn thành một cách đồng thời (không phải tuần tự), bạn có thể sử dụng Promise.all() kết hợp với await. Promise.all() nhận một mảng các Promises và trả về một Promise mới sẽ giải quyết khi tất cả các Promises trong mảng đều giải quyết thành công. Nếu bất kỳ Promise nào trong mảng bị từ chối, Promise được trả về bởi Promise.all() cũng sẽ bị từ chối ngay lập tức.
3.5. await Với Các Giá Trị Không Phải Promise
Mặc dù mục đích chính là chờ Promises, bạn cũng có thể sử dụng await trước các giá trị không phải Promise. Trong trường hợp này, await sẽ không tạm dừng việc thực thi mà ngay lập tức giải quyết thành giá trị đó. Mặc dù hợp lệ về mặt cú pháp, điều này ít khi hữu ích trong thực tế.
4. Async Await Trong Javascript Được Ứng Dụng Như Thế Nào?
async/await được ứng dụng rộng rãi trong JavaScript để đơn giản hóa việc xử lý các tác vụ bất đồng bộ trong nhiều trường hợp khác nhau:
4.1. Gọi API (Fetching Data from APIs)
Đây là trường hợp ứng dụng phổ biến nhất của async/await. Việc sử dụng async/await khi gọi các API giúp mã nguồn gọi API trở nên gọn gàng và dễ đọc hơn rất nhiều so với việc sử dụng chuỗi .then().
4.2. Đọc/Ghi Tệp Bất Đồng Bộ (Trong Node.js)
Trong môi trường Node.js, các module làm việc với hệ thống tệp (file system) thường cung cấp các API bất đồng bộ trả về Promises (hoặc hỗ trợ callbacks). async/await giúp việc đọc và ghi tệp trở nên đơn giản hơn.
4.3. Xử Lý Hoạt Động Định Thời (Handling Timed Operations)
Mặc dù setTimeout và setInterval truyền thống sử dụng callbacks, bạn có thể dễ dàng bọc chúng trong Promises để sử dụng với async/await khi cần tạm dừng luồng thực thi.
4.4. Tích hợp với các Thư viện Bất Đồng Bộ
Hầu hết các thư viện và framework JavaScript hiện đại làm việc với các tác vụ bất đồng bộ đều trả về Promises. Điều này làm cho async/await trở thành công cụ lý tưởng để làm việc với các thư viện này một cách dễ dàng và hiệu quả.
Đọc thêm:
5. Ưu Điểm Của Async Await So Với Callbacks và Promises
Việc sử dụng Async await là gì mang lại nhiều lợi ích so với các cách xử lý bất đồng bộ truyền thống:
- Mã nguồn dễ đọc và dễ hiểu: Giống mã đồng bộ, giảm gánh nặng nhận thức.
- Tránh "Callback Hell": Loại bỏ các vấn đề lồng nhau khó quản lý.
- Xử lý lỗi thuận tiện: Sử dụng try...catch quen thuộc.
- Dễ gỡ lỗi hơn: Có thể đặt breakpoint trong mã bất đồng bộ như mã đồng bộ.
6. Kết Luận
Async await là gì? Chúng là những từ khóa mạnh mẽ trong JavaScript, giúp đơn giản hóa việc làm việc với các tác vụ bất đồng bộ bằng cách cung cấp cú pháp thuận tiện hơn cho Promises. Bằng cách sử dụng async để đánh dấu hàm và await để tạm dừng thực thi cho đến khi Promise hoàn thành, các nhà phát triển có thể viết mã bất đồng bộ gọn gàng hơn, dễ đọc hơn và dễ bảo trì hơn. Việc nắm vững Async await là gì và Async await trong Javascript được ứng dụng như thế nào là kỹ năng cần thiết cho mọi nhà phát triển JavaScript hiện đại. Hãy áp dụng async/await vào các dự án của bạn để nâng cao chất lượng mã nguồn bất đồng bộ!