1. Async và Await trong JavaScript là gì?

Trước đây, để làm việc với code bất đồng bộ, chúng ta sử dụng callbackpromise . Async/Await là một cách mới để viết code bất đồng bộ, được Js giới thiệu từ bản cập nhật ES7. Nó được xây dựng trên Promise và tương thích với tất cả Promise dựa trên API. Nó cung cấp cho các ta 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.

Async – khai báo một hàm bất đồng bộ (async function someName(){…}). Các hàm bất đồng bộ sẽ luôn trả về một giá trị. Việc sử dụng async chỉ đơn giản là ngụ ý rằng một lời hứa sẽ được trả lại và nếu một lời hứa không được trả lại, Js sẽ tự động kết thúc nó. Khi gọi tới hàm async nó sẽ xử lý mọi thứ và được trả về kết quả trong hàm của nó. Async cũng cho phép sử dụng Await.

Await được sử dụng để chờ một Promise . Nó chỉ có thể được sử dụng bên trong một khối Async . Từ khóa Await làm cho Js đợi cho đến khi promise trả về kết quả. Cần lưu ý rằng nó chỉ làm cho khối chức năng không đồng bộ chờ đợi chứ không phải toàn bộ chương trình thực thi.

2. Cú pháp Async và Await trong JavaScript

2.1. Async

Cú pháp nó khá đơn giản. Từ khóa Async chỉ cần được đặt trước 1 hàm làm cho hàm trả về promise .

async function myFunction() {
  return "Hello";
}

Nó cũng giống như

async function myFunction() {
  return Promise.resolve("Hello");
}

Đây là cách sử dụng Promise :

myFunction().then(
  function(value) { /* code if successful */ },
  function(error) { /* code if some error */ }
);

Ví dụ cụ thể luôn nhé

<script>
function myDisplayer(some) {
  document.write(some);
}

async function myFunction() {return "laptrinhtudau";}

myFunction().then(
  function(value) {myDisplayer(value);},
  function(error) {myDisplayer(error);}
);
</script>

Hoặc đơn giản hơn, vì bạn muốn một giá trị bình thường (phản hồi bình thường, không phải lỗi):

<script>
function myDisplayer(some) {
  document.write(some);
}

async function myFunction() {return "laptrinhtudau";}

myFunction().then(
  function(value) {myDisplayer(value);}
);
</script>

2.2. Await

Từ khóa Await được đặt trước 1 hàm làm cho hàm chờ một promise . Từ khóa await chỉ có thể được sử dụng bên trong một hàm không đồng bộ.

let value = await promise;

Ví dụ:

<script>
async function myDisplay() {
  let myPromise = new Promise(function(resolve, reject) {
    resolve("I love You !!");
  });
  document.write(await myPromise);
}

myDisplay();
</script>

Hai đối số (resolve and reject) được Js xác định trước. Ta sẽ không tạo chúng nhưng gọi một trong số chúng khi hàm thực thi đã sẵn sàng.

3. Lưu ý khi sử dụng Async và Await trong JavaScript

3.1. Không thể sử dụng Await bên trong các hàm thông thường

Mình đã nói ở phần trên rồi và mình sẽ chỉ đưa ra ví dụ thôi nhé

function firstAsync() {
  let promise = Promise.resolve(10);
  let result = await promise; // Syntax error
}

Để hàm trên hoạt động bình thường, chúng ta cần thêm từ khóa async trước function firstAsync();

3.2. Async/Await thực hiện tuần tự

Đây không hẳn là điều xấu, nhưng thực hiện song song sẽ nhanh hơn nhiều.

async function sequence() {
  await promise1(50); // Wait 50ms…
  await promise2(50); // …then wait another 50ms.
  return "done!";
}

Đoạn code trên mất 100ms để hoàn thành, không phải một lượng thời gian lớn nhưng vẫn chậm. Điều này xảy ra là do nó đang diễn ra theo trình tự. Hai hàm được trả lại, cả hai đều mất 50ms để hoàn thành. Hàm thứ hai chỉ thực hiện sau khi hàm đầu tiên được giải quyết. Đây không phải là một thực tiễn tốt, vì các yêu cầu lớn có thể rất tốn thời gian. Chúng ta phải thực hiện song song.

Chúng ta có thể làm được điều đó bằng cách sử dụng Promise.all()

async function sequence() {
    await Promise.all([promise1(), promise2()]);  
    return "done!";
}

Hàm Promise.all() giải quyết khi tất cả promise hứa bên trong có thể lặp được giải quyết và sau đó trả về kết quả.

4. Xử lí lỗi với Async/Await

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 . Chúng ta chỉ cần để các await call của chúng ta vào trong khối try/catch như sau:

async function doSomethingAsync(){
      try {
          let result = await someAsyncCall();
      }
      catch(error) {
          // Nếu nó xảy ra, chúng tôi sẽ bắt lỗi ở đây.
      }  
  }

Nếu một promise giải quyết bình thường, sau đó await promise trả về kết quả. Nhưng trong trường hợp từ chối, nó sẽ ném lỗi, giống như có một câu lệnh throw tại dòng đó.

async function f() {
  await Promise.reject(new Error("Whoops!"));
}

Trong tình huống thực tế, promise có thể mất một thời gian trước khi nó từ chối. Trong trường hợp đó sẽ có độ trễ trước khi await đưa ra lỗi.

Chúng ta có thể bắt lỗi đó bằng cách sử dụng try..catch , giống như cách thông thường throw :

async function f() {

  try {
    let response = await fetch('http://no-such-url');
  } catch(err) {
    alert(err); // TypeError: failed to fetch
  }
}

f();