Async/await Trong JavaScript
Async / await
được giới thiệu bởi ES7 là một cải tiến từ promise mang đến điều tuyệt vời trong Asynchronous programming
với JavaScript. Nó cung cấp cho các developer js viết mã đồng bộ (synchronous) trên những chức năng không đồng bộ (asynchonous
), mà không làm gián đoạn code của chính mình. Tuy nhiên không hẳn những developer nào cũng có thể sử dụng chúng một cách hiệu quả và sâu hơn nữa là hiểu cốt lõi của việc sử dụng chúng. Trong bài viết này chúng ta sẽ cùng nhau khám phá về của async / await
qua các ví dụ.
Async / Await là một tính năng của JavaScript giúp chúng ta làm việc với các hàm bất đồng bộ theo cách thú vị hơn và dễ hiểu hơn. Nó được xây dựng trên promise
và tương thích với tất cả các promise
dựa trên API. Đầu tiên chúng ta hãy bắt đầu với async
trước.
Async functions
Async
functions là hàm bất đồng bộ. Nó có thể được sử dụng như sau:
async function f() {
return 1;
}
Một function luôn trả về một promise. Các giá trị khác được bao bọc trong một promise đã được giải quyết tự động. Ví dụ, hàm này trả về một promise đã giải quyết với kết quả là 1
async function f() {
return 1;
}
f().then(alert); // 1
Chúng ta có thể trả lại một promise
theo cách khác như sau:
async function f() {
return Promise.resolve(1);
}
f().then(alert); // 1
Vì vậy, hãy đảm bảo rằng hàm async
trả về một promise. Nhưng không chỉ có vậy. Chúng ta có thể dùng await
. Nó chỉ hoạt động bên trong các async
functions.
Await
Cú pháp:
// works only inside async functions
let value = await promise;
await
khi được đặt trước một promise, nó sẽ đợi cho đến khi promise kết thúc và trả về kết quả. Dưới đây là một ví dụ với một promise sẽ được xử lí trong 1 giây:
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("done!"), 1000)
});
let result = await promise; // wait until the promise resolves (*)
alert(result); // "done!"
}
f();
Hiểu await
theo đúng nghĩa đen thì ban đầu nó sẽ tạm dừng việc thực thi hàm cho đến khi promise được giải quyết, và sau đó nó sẽ tiếp tục khi promise đó được xử lí xong. Điều đó không tốn bất kỳ tài nguyên CPU nào, vì JavaScript có thể thực hiện các công việc khác trong thời gian chờ đợi: thực thi các tập lệnh khác, xử lý các sự kiện, v.v.
Error handling
Nếu một promise được xử lí bình thường, thì await promise
sẽ trả về kết quả. Nhưng trong trường hợp bị từ chối, nó sẽ tạo ra lỗi, giống như thể có một câu lệnh throw
ở dòng đó. Ví dụ
async function f() {
await Promise.reject(new Error("Whoops!"));
}
Nó sẽ bị lỗi như dưới đây trong trường hợp bị từ chối:
async function f() {
throw new Error("Whoops!");
}
Trong các tình huống thực tế, promise có thể mất một thời gian trước khi bị từ chối. Trong trường hợp đó sẽ có một khoảng thời gian trễ trước khi await
sinh ra một lỗi. Một điều tuyệt vời khác về Async / Await là nó cho phép chúng ta bắt các lỗi không mong đợi bằng cách sử dụng try / catch
async function f() {
try {
let response = await fetch('http://no-such-url');
} catch(err) {
alert(err); // TypeError: failed to fetch
}
}
f();
- Mệnh đề
catch
sẽ xử lý các lỗi gây ra bởi các hàm bất đồng bộ hoặc bất kỳ lỗi nào chúng ta có thể đã viết bên trong khốitry
.
async function f() {
try {
let response = await fetch('/no-user-here');
let user = await response.json();
} catch(err) {
// catches errors both in fetch and response.json
alert(err);
}
}
f();
Nếu chúng ta không có try..catch
, thì promise
được tạo bởi lệnh gọi của hàm bất đồng bộ f()
sẽ bị từ chối. Vì vậy chúng ta cần thêm .catch
vào để xử lý nó:
async function f() {
let response = await fetch('http://no-such-url');
}
// f() becomes a rejected promise
f().catch(alert); // TypeError: failed to fetch // (*)
Nếu chúng ta quên thêm vào .catch đó, thì chúng ta sẽ gặp lỗi promise. Chúng ta có thể bắt gặp các lỗi như vậy bằng cách sử dụng unhandled rejection
như được mô tả trong bài Error handling with promise
Tổng kết
Việc sử dụng async/await
có một số ưu điểm vượt trội:
- Code dễ đọc hơn rất rất nhiều, không cần phải
then
rồicatch
, chỉ viết như bình thường, sau đó dùngtry/catch
để bắt lỗi. - Debug dễ hơn nhiều, vì mỗi lần dùng
await
được tính là một dòng code, do đó ta có thể đặt debugger đểdebug
từng dòng như thường. - Khi có lỗi,
exception
sẽ chỉ ra lỗi ở dòng số mấy chứ không chung chung làun-resolved promise
. - Với promise hoặc
callback
, việc kết hợpif/else
hoặc retry với codeasynchnous
là một điều gì đó khá khó chịu. Vớiasync/await
, việc này vô cùng dễ dàng.
Vậy là series tìm hiểu về promise,
async
/
await
của chúng ta đã khép lại. Các bạn truy cập Fanpage của Suntech để tìm kiếm các thông tin về khóa học và việc làm tại đây. Hẹn gặp lại các bạn trong các bài học khác!