Thứ sáu, 04/09/2020 | 00:00 GMT+7

Khám phá các hàm Async / Await trong JavaScript

Lời hứa cung cấp cho ta một cách dễ dàng hơn để đối phó với sự không đồng bộ trong mã của ta theo cách tuần tự. Xem xét rằng bộ não của ta không được thiết kế để đối phó với sự không đồng bộ một cách hiệu quả, đây là một bổ sung đáng hoan nghênh. Các chức năng async / await , một bổ sung mới với ES2017 ( ES8 ), giúp ta nhiều hơn nữa trong việc cho phép ta viết mã hoàn toàn đồng bộ trong khi thực hiện các việc không đồng bộ đằng sau mức thấp .

Chức năng đạt được bằng cách sử dụng các hàm không đồng bộ có thể được tạo lại bằng cách kết hợp các lời hứa với trình tạo , nhưng các hàm không đồng bộ cung cấp cho ta những gì ta cần mà không cần thêm bất kỳ mã soạn sẵn nào.

Ví dụ đơn giản

Trong ví dụ sau, trước tiên ta khai báo một hàm trả về một lời hứa sẽ phân giải thành giá trị 🤡 sau 2 giây. Sau đó ta tuyên bố một chức năng asyncchờ đợi cho lời hứa quyết tâm trước khi đăng thông điệp ra cửa sổ Console:

function scaryClown() {   return new Promise(resolve => {     setTimeout(() => {       resolve('🤡');     }, 2000);   }); }  async function msg() {   const msg = await scaryClown();   console.log('Message:', msg); }  msg(); // Message: 🤡 <-- after 2 seconds 

await là một toán tử mới được sử dụng để chờ một lời hứa giải quyết hoặc từ chối. Nó chỉ được dùng bên trong một hàm không đồng bộ.

Sức mạnh của các hàm không đồng bộ trở nên rõ ràng hơn khi có nhiều bước liên quan:

function who() {   return new Promise(resolve => {     setTimeout(() => {       resolve('🤡');     }, 200);   }); }  function what() {   return new Promise(resolve => {     setTimeout(() => {       resolve('lurks');     }, 300);   }); }  function where() {   return new Promise(resolve => {     setTimeout(() => {       resolve('in the shadows');     }, 500);   }); }  async function msg() {   const a = await who();   const b = await what();   const c = await where();    console.log(`${ a } ${ b } ${ c }`); }  msg(); // 🤡 lurks in the shadows <-- after 1 second 

Tuy nhiên, một lời cảnh báo, trong ví dụ trên, mỗi bước được thực hiện tuần tự, với mỗi bước bổ sung phải đợi bước trước giải quyết hoặc từ chối trước khi tiếp tục. Thay vào đó, nếu bạn muốn các bước diễn ra song song, bạn có thể chỉ cần sử dụng Promise.all để đợi tất cả các lời hứa đã hoàn thành:

// ...  async function msg() {   const [a, b, c] = await Promise.all([who(), what(), where()]);    console.log(`${ a } ${ b } ${ c }`); }  msg(); // 🤡 lurks in the shadows <-- after 500ms 

Promise.all trả về một mảng với các giá trị được giải quyết sau khi tất cả các lời hứa được chuyển vào đã được giải quyết.

Trong phần trên, ta cũng sử dụng một số cách cấu trúc mảng đẹp để làm cho mã của ta ngắn gọn.

Hứa hẹn-Trả lại

Các hàm không đồng bộ luôn trả về một lời hứa, vì vậy những điều sau có thể không tạo ra kết quả mà bạn đang theo đuổi:

async function hello() {   return 'Hello Alligator!'; }  const b = hello();  console.log(b); // [object Promise] { ... } 

Vì những gì được trả lại là một lời hứa, bạn có thể làm điều gì đó như sau:

async function hello() {   return 'Hello Alligator!'; }  const b = hello();  b.then(x => console.log(x)); // Hello Alligator! 

… Hoặc chỉ thế này:

async function hello() {   return 'Hello Alligator!'; }  hello().then(x => console.log(x)); // Hello Alligator! 

Các hình thức khác nhau

Cho đến nay với các ví dụ của ta , ta đã thấy hàm không đồng bộ như một khai báo hàm, nhưng bạn cũng có thể xác định các biểu thức hàm không đồng bộ và các hàm mũi tên không đồng bộ:

Biểu thức hàm không đồng bộ

Đây là hàm không đồng bộ từ ví dụ đầu tiên của ta , nhưng được định nghĩa là một biểu thức hàm:

const msg = async function() {   const msg = await scaryClown();   console.log('Message:', msg); } 

Hàm mũi tên không đồng bộ

Đây là ví dụ tương tự , nhưng lần này được định nghĩa là một hàm mũi tên:

const msg = async () => {   const msg = await scaryClown();   console.log('Message:', msg); } 

Xử lý lỗi

Một điều khác rất hay về các hàm không đồng bộ là việc xử lý lỗi cũng được thực hiện hoàn toàn đồng bộ, sử dụng các câu lệnh try… catch cũ tốt. Hãy chứng minh bằng cách sử dụng một lời hứa sẽ từ chối một nửa thời gian:

function yayOrNay() {   return new Promise((resolve, reject) => {     const val = Math.round(Math.random() * 1); // 0 or 1, at random      val ? resolve('Lucky!!') : reject('Nope 😠');   }); }  async function msg() {   try {     const msg = await yayOrNay();     console.log(msg);   } catch(err) {     console.log(err);   } }  msg(); // Lucky!! msg(); // Lucky!! msg(); // Lucky!! msg(); // Nope 😠 msg(); // Lucky!! msg(); // Nope 😠 msg(); // Nope 😠 msg(); // Nope 😠 msg(); // Nope 😠 msg(); // Lucky!! 

Cho rằng các hàm không đồng bộ luôn trả về một lời hứa, bạn cũng có thể xử lý các lỗi chưa được xử lý như bạn thường sử dụng câu lệnh catch:

async function msg() {   const msg = await yayOrNay();   console.log(msg); }  msg().catch(x => console.log(x)); 

Việc xử lý lỗi đồng bộ này không chỉ hoạt động khi một lời hứa bị từ chối mà còn khi có thời gian chạy thực tế hoặc lỗi cú pháp xảy ra. Trong ví dụ sau, lần thứ hai với lệnh gọi hàm msg, ta chuyển vào một giá trị số không có phương thức toUpperCase trong chuỗi nguyên mẫu của nó. Khối try… catch của ta cũng bắt được lỗi đó:

function caserUpper(val) {   return new Promise((resolve, reject) => {     resolve(val.toUpperCase());   }); }  async function msg(x) {   try {     const msg = await caserUpper(x);     console.log(msg);   } catch(err) {     console.log('Ohh no:', err.message);   } }  msg('Hello'); // HELLO msg(34); // Ohh no: val.toUpperCase is not a function 

Chức năng không đồng bộ với APIS dựa trên hứa hẹn

Như ta đã trình bày trong phần sơ lược về API Tìm nạp , các API web dựa trên lời hứa là một thành phần hoàn hảo cho các hàm không đồng bộ:

async function fetchUsers(endpoint) {   const res = await fetch(endpoint);   let data = await res.json();    data = data.map(user => user.username);    console.log(data); }  fetchUsers('https://jsonplaceholder.typicode.com/users'); // ["Bret", "Antonette", "Samantha", "Karianne", "Kamren", "Leopoldo_Corkery", "Elwyn.Skiles", "Maxime_Nienow", "Delphine", "Moriah.Stanton"] 

Hỗ trợ trình duyệt:
Tính đến năm 2020, 94% trình duyệt trên toàn thế giới có thể xử lý async / await trong javascript Ngoại lệ đáng chú ý là IE11 và Opera Mini.

Kết luận

Trước các hàm Async / await, mã JavaScript dựa vào rất nhiều sự kiện không đồng bộ (ví dụ: mã thực hiện nhiều lệnh gọi đến API) sẽ kết thúc trong cái mà một số người gọi là “địa ngục gọi lại” - Một chuỗi các hàm và lệnh gọi lại rất khó để đọc và hiểu.

Không đồng bộ và chờ đợi cho phép ta viết mã JavaScript không đồng bộ đọc rõ ràng hơn nhiều.


Tags:

Các tin liên quan

module ES6 và Cách sử dụng Nhập và Xuất trong JavaScript
2020-09-04
Giải thích về phương pháp rút gọn JavaScript
2020-09-04
filter () Phương thức mảng trong JavaScript
2020-09-03
Hiểu các hàm mũi tên trong JavaScript
2020-07-31
Cách tạo phần tử kéo và thả với Vanilla JavaScript và HTML
2020-07-27
Hiểu các chữ mẫu trong JavaScript
2020-06-30
Cách sử dụng .map () để lặp lại thông qua các mục mảng trong JavaScript
2020-05-19
Hiểu về cấu trúc hủy, tham số khôi phục và cú pháp trải rộng trong JavaScript
2020-05-12
Cách gỡ lỗi JavaScript với Google Chrome DevTools và Visual Studio Code
2020-05-08
Thanh tiến trình trang với các biến JavaScript và CSS
2020-04-16