Async/Await Trong Javascript Có Làm Khó Được Bạn?

Mọi ngôn ngữ lập trình đều không hoàn hảo, nó sẽ luôn có những ưu và nhược điểm riêng. Javascript – một trong những ngôn ngữ lập trình phổ biến nhất hiện nay, đã phải trải qua một khoảng thời gian dài khó khăn khi phải dựa vào callbacks để lập trình các đoạn code bất đồng bộ. Sau đó trong bản cập nhật ES7, JavaScript đã đưa ra một giải pháp mới được cộng đồng lập trình rất ủng hộ để giải quyết cái bài toàn bất đồng bộ chính là Async/Await.

Async / Await 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 Javascript 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. Trong đó:

Async được dùng để khai báo một hàm bất đồng bộ. 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, JavaScript sẽ tự động kết thúc nó.

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 JavaScript đợ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.

Cú pháp Async / Await

1. Async

Từ khóa Async được đặt trước 1 hàm làm cho hàm trả về promise.

Ví dụ:

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

Tương tự như trên :

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

Dưới đây là cách sử dụng Promise :

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

2. Await

Từ khóa Await được đặt trước 1 hàm làm cho hàm chờ một promise.

let value = await promise;

Từ khóa await chỉ có thể được sử dụng bên trong một hàm không đồng bộ.

Ví dụ:







JavaScript async / await

Output:

Những điều cần chú ý quan tâm khi sử dụng Async / Await

1. Chúng ta không hề sử dụng Await bên trong những hàm thường thì

Ví dụ:

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();

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

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

Ví dụ:

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

Đoạn code trên mất 100 ms để triển khai xong, không phải một lượng thời hạn 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 50 ms để hoàn thành xong. Hàm thứ hai chỉ triển khai sau khi hàm tiên phong được xử lý. Đây không phải là một thực tiễn tốt, vì những nhu yếu lớn hoàn toàn có thể rất tốn thời hạn. Chúng ta phải thực thi song song .

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

Theo MDN: “Phương thức Promise.all(iterable) trả ra một Promise mới và promise mới này chỉ được kết thúc khi tất cả các promise trong iterable kết thúc hoặc có một promise nào đó xử lý thất bại. Kết quả của promise mới này là một mảng chứa kết quả của tất cả các promise theo đúng thứ tự hoặc kết quả lỗi của promise gây lỗi.”

Ví dụ:

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

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

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

Kết quả bình thường khi bạn sử dụng async/await là một kết quả đã được resolve. Nhưng khi promise bị reject và exception xảy ra thì phải làm gì? Chúng ta có thể dùng try…catch để giải quyết các lỗi này như các hàm bình thường khác.

Ví dụ:

Nếu một promise giải quyết bình thường, sau đó await promisetrả 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ế, lời hứa 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();

Tại sao nên dùng Async / Await ?

1. Ngắn gọn và thật sạch

Ưu điểm đơn giản nhất chính là số lượng code ta cần viết đã giảm đi đáng kể. Không cần phải then rồi catch gì cả, chỉ viết như code chạy tuần tự, sau đó dùng try/catch thông thường để bắt lỗi.

2. Xử lí lỗi

Async/await giúp ta xử lý cả error đồng bộ lẫn error bất đồng bộ theo cùng 1 cấu trúc. Tạm biệt try/catch. Với đoạn code dưới dùng promise, try/catch sẽ không bắt được lỗi nếu JSON.parselỗi do nó xảy ra bên trong promise. Ta cần gọi  .catch bên trong promise và lặp lại code xử lý error, điều mà chắc chắn sẽ trở nên rắc rối hơn cả console.logtrong đoạn code production.

const makeRequest = () => {
  try {
    getJSON()
      .then(result => {
        // this parse may fail
        const data = JSON.parse(result)
        console.log(data)
      })
      // uncomment this block to handle asynchronous errors
      // .catch((err) => {
      //   console.log(err)
      // })
  } catch (err) {
    console.log(err)
  }

Bây giờ hãy nhìn vào đoạn code sử dụng async/await. Khối catchgiờ sẽ xử lý các lỗi parsing.

const makeRequest = async () => {
  try {
    // this parse may fail
    const data = JSON.parse(await getJSON())
    console.log(data)
  } catch (err) {
    console.log(err)
  }
}

3. Câu lệnh điều kiện kèm theo

Hãy tưởng tượng một cái gì đó giống như đoạn mã bên dưới tìm nạp 1 số ít tài liệu và quyết định hành động xem nó có nên trả lại tài liệu đó hay không hoặc lấy thêm chi tiết cụ thể dựa trên một số ít giá trị trong tài liệu .

const makeRequest = () => {
  return getJSON()
    .then(data => {
      if (data.needsAnotherRequest) {
        return makeAnotherRequest(data)
          .then(moreData => {
            console.log(moreData)
            return moreData
          })
      } else {
        console.log(data)
        return data
      }
    })
}

Chỉ nhìn vào đoạn code trên thôi cũng đã khiến bạn đau đầu. Thật thuận tiện bị lạc trong toàn bộ những câu lệnh lồng nhau ( 6 Lever ), dấu ngoặc nhọn và trả về chỉ thiết yếu để truyền tải hiệu quả ở đầu cuối cho đến hàm chính .
Khi sử dụng async / await, ta sẽ có đoạn code mới dễ đọc hơn .

const makeRequest = async () => {
  const data = await getJSON()
  if (data.needsAnotherRequest) {
    const moreData = await makeAnotherRequest(data);
    console.log(moreData)
    return moreData
  } else {
    console.log(data)
    return data    
  }
}

Với promise hoặc callback, việc phối hợp if / else hoặc retry với code asynchnous là một cực hình vì ta phải viết code lòng vòng, rắc rối. Với async / await, việc này vô cùng thuận tiện .

4. Debug

Cuối cùng khi bạn thao tác với async / await, việc debug trở nên rất đơn thuần. Với async / await, bạn không cần nhiều những arrow function và bạn hoàn toàn có thể thực thi những cuộc gọi chờ đúng chuẩn như thể chúng là những cuộc gọi đồng điệu thường thì .

Mỗi lần dùng await được tính là một dòng code, do đó ta có thể đặt debugger để debug từng dòng như thường.

Tạm kết

Như vậy, trong bài viết này tất cả chúng ta đã cũng khám phá những yếu tố cơ bản về Async / Await trong Javascript. Nếu những bạn thấy bài viết hữu dụng hãy rate 5 * và share cho mọi người tìm hiểu thêm !
Hãy để lại comment để mình hoàn toàn có thể triển khai xong bản thân hơn trong tương lai. Cám ơn những bạn !
Nguồn tìm hiểu thêm :

ĐÁNH GIÁ post
Bài viết liên quan

Tư vấn miễn phí (24/7) 094 179 2255