Async/await
Từ phiên bản ES2017, Javascript đã thêm hai từ khóa async
và await
. Đây là các cú pháp thay thế cho cú pháp cũ là constructor Promise()
, hàm then()
, catch()
, còn bản chất Promise vẫn giữ nguyên.
Hàm async
Từ khóa async
đặt trước hàm để chuyển hàm đó từ hàm đồng bộ sang thành hàm bất đồng bộ (async function). Hàm bất đồng bộ khi thực thi sẽ trả về một Promise.
Ví dụ về hàm async
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
async function hello() { return "Hello asyc" } // hàm thông thường
let hello1 = async function() { return "Hello express" }; // biểu thức hàm
let hello2 = async () => "Hello arrow"; // hàm mũi tên
class Person {
async greeting() { // phương thức async
return "Hello method";
};
}
// sử dụng hàm bất đồng bộ
hello().then((message) => console.log(message)); // Hello asyc
hello1().then((message) => console.log(message)); // Hello express
hello2().then((message) => console.log(message)); // Hello arrow
// Hello method
new Person().greeting().then(message => console.log(message));
|
Trong ví dụ trên hàm hello()
ở trên tương đương với:
1
2
3
|
function hello() {
return Promise.resolve("Hello asyc");
}
|
Từ khóa await
Từ khóa await
đặt trước biểu thức Promise để lấy giá trị trả về. Từ khóa await
phải đặt trong hàm async
. Khi gặp câu lệnh với từ khóa await
, Promise phải thực thi xong mới chạy câu lệnh tiếp theo. Tức là các câu lênh await
sẽ chuyển thực thi Promise bất đồng bộ thành chạy tuần tự.
Ví dụ đơn giản sử dụng await:
1
2
3
4
5
6
7
|
async function hello() {
// đặt trước string sẽ chuyển string thành Promise
let message = await "Hello asyc";
return message;
};
hello().then((message) => console.log(message)); // Hello asyc
|
Ví dụ khác sử dụng await:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
// promise1 và promise2 là hàm trả về Promise
const promise1 = () => new Promise((resolve, reject) => {
setTimeout(resolve, 500, 123);
});
const promise2 = () => new Promise((resolve, reject) => {
setTimeout(resolve, 100, 456);
});
async function getNumber() {
// promise1 chạy xong đến promise2 sẽ chạy
// mất thời gian tổng cộng 600ms
let firstNumber = await promise1();
let secondNumber = await promise2();
return firstNumber + secondNumber;
};
getNumber().then((number) => console.log(number)); // 579
|
Hàm setNumber()
ở ví dụ trên có thể viết lại như sau:
1
2
3
4
5
6
7
|
function getNumber() {
let firstNumber, secondNumber;
return Promise.resolve()
.then(() => promise1().then(number => firstNumber = number))
.then(() => promise2().then(number => secondNumber = number))
.then(() => firstNumber + secondNumber);
};
|
Chúng ta thấy rằng viết Promise theo kiểu async/await
như ví dụ trước là dễ đọc và dễ hiểu tương tự cú pháp thông thường.
Quản lý lỗi với try-catch
Chúng ta sử dụng try-catch
thay cho hàm catch()
để quản lý lỗi với Promise sử dụng async/await
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
const promise1 = () => new Promise((resolve, reject) => {
setTimeout(reject, 500, 123);
});
const promise2 = () => new Promise((resolve, reject) => {
setTimeout(resolve, 100, 456);
});
async function getNumber() {
try {
let firstNumber = await promise1();
let secondNumber = await promise2();
return firstNumber + secondNumber;
} catch (error) {
console.error('Lỗi trong promise ' + error.toString()); // 123
}
};
getNumber();
|
Chạy promise đồng thời với Promise.all()
Toán tử await sẽ chạy các promise tuần tự, để chạy đồng thời hãy sử dụng hàm Promise.all
Ví dụ sau chạy đồng thời hai promise nên thời gian sẽ chạy ít hơn ví dụ trước 100ms.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
const promise1 = () => new Promise((resolve, reject) => {
setTimeout(resolve, 500, 123);
});
const promise2 = () => new Promise((resolve, reject) => {
setTimeout(resolve, 100, 456);
});
async function getNumber() {
// chạy song song nên thời gian chạy là khoảng 500ms
return Promise.all([promise1(), promise2()])
.then(([firstNumber, secondNumber]) => firstNumber + secondNumber)
};
getNumber().then((number) => console.log(number)); // 579
|