12/08/2018, 16:25

Js hành trình từ Callback đến Async/Await

Chào các bạn, Bản release chính thức ECMAScript 8 được giới thiệu vào cuối tháng 6 vừa rồi đã bổ sung Async function cho việc sử lý các đoạn mã bất đồng bộ trong Js một cách dễ dàng hơn. Nhưng đợi đã, trước khi đi vào tìm hiểu Async function là gì, tại sao nó làm cho code xử lý bất đồng bộ ...

Chào các bạn,

Bản release chính thức ECMAScript 8 được giới thiệu vào cuối tháng 6 vừa rồi đã bổ sung Async function cho việc sử lý các đoạn mã bất đồng bộ trong Js một cách dễ dàng hơn.

Nhưng đợi đã, trước khi đi vào tìm hiểu Async function là gì, tại sao nó làm cho code xử lý bất đồng bộ của ta sáng sủa và dễ dàng hơn thì chúng ta sẽ dạo qua một số cách xử lý bất đồng bộ trước đây ta từng làm trong Js

Một cách phổ biến mà trước đây chúng ta hay làm cho vấn đề xử lý các code bất đồng bộ là xử dụng callback. Để xử dụng Callback ta sẽ đặt 1 biến tham chiếu tới function, sau đó truyền vào function khác để thực thi ngay sau khi function đó thực thi xong. Ví dụ về việc sử dụng callback

// Execute the function "doThis" with another function as parameter, in this case "andThenThis". doThis will execute whatever code it has and when it finishes it should have "andThenThis" being executed.
doThis(andThenThis)
// Inside of "doThis" it's referenced as "callback" which is just a variable that is holding the reference to this function
function andThenThis() {
  console.log('and then this')
}
// You can name it whatever you want, "callback" is common approach
function doThis(callback) {
  console.log('this first')
  
  // the '()' is when you are telling your code to execute the function reference else it will just log the reference callback()
}

Và vấn đề thực sự xảy ra khi chúng ta cần thao với nhiều hàm bất đồng bộ hơn.

getData(function(a){  
    getMoreData(a, function(b){
        getMoreData(b, function(c){ 
            getMoreData(c, function(d){ 
                getMoreData(d, function(e){ 
                    ...
                });
            });
        });
    });
});

"pyramid of doom" kim tự tháp dom, như bạn thấy ở trên, làm cho việc controll thực hiện các công việc thực sử khó khi xảy ra lỗi, ta sẽ rất khó để tracking việc thực thi của chúng ra sao. Và rồi Promises ra đời.

Sử dụng Promises giúp cho code của chúng ta dễ đọc hơn, dễ clear hơn về thứ tự thực thi của code. Ví dụ về việc khởi tạo 1 promise

const myPromise = new Promise(function(resolve, reject) {
  
  // code here
  
  if (codeIsFine) {
    resolve('fine')
  } else {
    reject('error')
  }
})
myPromise
  .then(function whenOk(response) {
    console.log(response)
    return response
  })
  .catch(function notOk(err) {
    console.error(err)
  }

Đi sâu chút về việc phân tích code trên:

  • 1 promise khởi tạo 1 function có 2 trạn thái là resolvereject
  • Viết code async bên trong function promise, resolve sẽ xảy ra khi mọi thứ được thực thi như đúng mong muốn, ngược lại thì sẽ là reject
  • Khi trạng thái resolve được tìm thấy, .then method sẽ được thực thi.
  • Khi trạng thái reject được tìm thấy thì .catch sẽ được trigger.

1 ví dụ khác về Promises:

remotedb.allDocs(...).then(function (resultOfAllDocs) {
  return localdb.put(...);
}).then(function (resultOfPut) {
  return localdb.get(...);
}).then(function (resultOfGet) {
  return localdb.put(...);
}).catch(function (err) {
  console.log(err);
});

Như bạn thấy trong ví dụ trên, chúng ta đã thấy được sự clear hơn khi sử dụng callback. Nhưng vấn đề cũng thực sự nằm tại đây, chúng ta vẫn tiếp tục sử dụng 1 pyramid of doom giống với callback. Việc lặp lại các promise này khiến cho code của chúng ta sẽ thiếu trực quan.

Và bây giờ chúng ta sẽ đi đến 1 giải pháp mới nhất cho vấn đề Asynchronous trong Js đó chính là Async/await function. Phuơng pháp này dường như là sự pha trộn, kết hợp với promise. Theo cách này thì chúng ta chỉ cần khai báo function là async và nhưng gì trong thân method phải có là await cho 1 promise đến hoàn thành. Ví dụ:

sumTwentyAfterTwoSeconds(10)
  .then(result => console.log('after 2 seconds', result))
async function sumTwentyAfterTwoSeconds(value) {
  const remainder = afterTwoSeconds(20)
  return value + await remainder
}
function afterTwoSeconds(value) {
  return new Promise(resolve => {
    setTimeout(() => { resolve(value) }, 2000);
  });
}

Trong ví dụ này chúng ta đã khai báo function sumTwentyAfterTwoSeconds là async function

  • Khai báo việc wait để resove hoặc reject cho promise function afterTwoSeconds
  • Việc thự thi chức năng cộng chi xảy ra khi quá trình await trên được hoàn thành.

Trên đây là những cách mà bạn có thể sử lý khi tao tác, xử lý các vấn đề về asynchonous trong JS. Hi vọng nó giúp ích cho bạn. Thanks for reading!!!

0