Khám phá Async/Await trong JavaScript

    

1. Introduction

    Promise trước đó đã được giới thiệu là một cơ chế nổi bật, cung cấp cho chúng ta một cách dễ dàng để xử lý bất đồng bộ.

    Promise còn giúp chúng ta thoát khỏi những callback hell hay pyramid of doom ( những hàm callback lồng nhau không điểm dừng, mà trước đó chúng ta thường sử dụng setTimeout để xử lí) - Đọc thêm Promise

    Async/await functions là một bổ sung mới với ES2017 (ES8), giúp chúng ta nhiều hơn trong việc thực hiện các thao tác bất đồng bộ một cách tuần tự.

    Một bí mật là Async/await functions vẫn sử dùng Promise bên dưới nhưng code bạn viết trông sẽ clean hơn

2. Simple Example

    Trong ví dụ sau, trước tiên chúng ta khai báo một hàm trả về một Promise sẽ resolves ra giá trị 🤡 sau 2 giây.

    Sau đó, chúng ta khai báo một hàm async/ await và chờ Promise trả ra kết quả trước khi log được xuất hiện

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 Promise resolve hoặc reject. Nó chỉ có thể được sử dụng bên trong một hàm async

    Sức mạnh của hàm async trở nên mạnh mẽ hơn khi xử lí chuỗi các hàm kéo theo 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, trong ví dụ trên, mỗi hàm được thực hiện tuần tự, với mỗi hàm tiếp sau phải đợi bước trước resolve hoặc reject trước khi tiếp tục.

    Thay vào đó, nếu bạn muốn các hàm đồng thời chạy song song, bạn chỉ cần sử dụng Promise.all để đợi tất cả các Promise 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 resolve sau khi tất cả các Promise đã được giải quyết.

3. Promise-Returning

    Các hàm Async luôn trả về một Promise, vì vậy những đoạn code sau đây có thể sẽ không tạo ra kết quả như bạn mong muốn:

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 promise, thay vào đó, 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:

async function hello() {
  return 'Hello Alligator!';
}

hello().then(x => console.log(x)); // Hello Alligator!

4. Different Forms

    Từ đầu các ví dụ, chúng ta chỉ thấy hàm async như một function declaration, nhưng bạn cũng có thể định nghĩa async như một function expressions hoặc thống qua arrow function đọc thêm về function declaration và function expressions

4.1 Async Function Expression

    Đây là hàm bất đồng bộ từ ví dụ đầu tiên, nhưng có thể được định nghĩa giống như là function expression:

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

4.2 Async Arrow Function

    Đây là ví dụ tương tự một lần nữa, nhưng lần này được định nghĩa dưới dạng arrow function:

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

5. Error Handling

    Một điều khác rất hay về hàm async là việc xử lý lỗi cũng được thực hiện hoàn toàn đồng bộ, sử dụng câu lệnh try… catch cũ.

    Để chứng minh bằng cách sử dụng một Promise sẽ reject một nửa số lần:

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!!

    Các hàm async luôn trả về một Promise, 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 Promise bị reject mà còn khi có timeout thời gian chạy 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, chúng tôi chuyển vào một giá trị số không có phương thức toUpperCase. Khối try… catch 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

6. Async Functions With Promise-Based APIS

    Hầu hết các API web mà promise-based là đều sử dụng các hàm async:

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"]

7. Kết luận

    Bên trên là những gì mình tìm hiểu về Async/Await, hi vọng giúp ích được cho mọi người

8. Tài liệu tham khảo

    6 lí do Async/Await đánh bại Promise

    Promise es6

    Function declaration và Function expressions

    Async/Await

Nguồn: Viblo

Bình luận
Vui lòng đăng nhập để bình luận
Một số bài viết liên quan