Tóm Tắt
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