Sao có thể làm chủ Async/Await với ví dụ thực tế

Giời thiệu

Async / await là một cách mới để viết mã bất đồng bộ. Nó được xây dựng dựa trên lời hứa, do đó, nó cũng non blocking.
Trước đây chúng ta chỉ có hai lựa chọn là callbacks và promies.

Callbacks

setTimeout(() => {
  console.log('This runs after 1000 milliseconds.');
}, 1000);

Vấn đề của callbacks - callbacks hell

callbacks nồng nhau trông như thế này:

    asyncCallOne(){
        asyncCallTwo(){
            asyncCallThree(){
                asyncCallFour(){
                    asyncCallFive(){
                        asyncCallSix(){
                            asyncCallSeven(){
                                asyncCallEight(){
                                    asyncCallNight(){
                                        asyncCallTen(){
                                            // do something here...
                                        }
                                    }
                                }
                             }
                        }
                     }
                }
             }
        }
    }

Callback Hell Là các callback được giọ sâu nhiều cấp như trên, nó sẽ gây khó hiểu và khó mà maintain được code.

Promises

const promiseFunction = new Promise((resolve, reject) => {
  const add = (a, b) => a + b;
  resolve(add(2, 2));
});
promiseFunction.then((response) => {
  console.log(response);
}).catch((error) => {
  console.log(error);
})

promiseFunction sẽ trả về một Promies là một tiến trình thực thi của hàm đó. Hàm resolve là tín hiệu để Promise kết thúc. Sau đó ta dùng .then() và .catch() lên promise function: then - trả về một callback nếu promise trả về kết quả thành công catch - trả về một callback nếu promise trả về lỗi.

Async Functions

Async function cho chúng ta một cú pháp ngắn gọn và rõ ràng cho phép cũng ta viết được code ngắn gọn hơn mà kết quả trả về cũng giống như với promies. Async không khác gì mấy so với promises. Async function được tạo bởi từ async trước function trông giống như:

const asyncFunction = async () => {
  // Code
}

Asynchronous functions có thể 'dừng' với await, keyword mà chúng ta chỉ có thể sử dụng bên trong async function. Await trả về bất cứ thứ gì mà khi function xong. Sự khác nhau giữa promises và async/await:

// Async/Await
const asyncGreeting = async () => 'Greetings';
// Promises
const promiseGreeting = () => new Promise(((resolve) => {
  resolve('Greetings');
}));
asyncGreeting().then(result => console.log(result));
promiseGreeting().then(result => console.log(result));

Async/Await trông giống như code đồng bộ, và code đồng bộ thì dễ hiểu hơn. Bây giờ là ví dụ thực tế.

Bộ chuyển đổi tiền tệ

Mô tả và thiết lập dự án

Chúng ta sẽ tạo một ví dụ đơn giản nhưng hữu dụng giúp chúng ta nắm dõ về Async/Await.
Chương trình sẽ lấy mã tiền tệ mà chúng tôi muốn chuyển đổi và mã tiền tệ chúng tôi muốn chuyển đổi, cũng như số tiền. Sau đó, chương trình sẽ đưa ra tỷ giá hối đoái chính xác dựa trên dữ liệu từ các API.
Trong ứng dụng này, chúng tôi sẽ nhận dữ liệu từ hai nguồn không đồng bộ:

  1. Currency Layer --- https://currencylayer.com Bạn cần phải đăng ký miễn phí để có thể sử dụng Khóa truy cập API. API này sẽ cung cấp cho chúng tôi dữ liệu cần thiết để tính tỷ giá hối đoái giữa các loại tiền tệ.
  2. untries — http://restcountries.eu/  -- API này sẽ cung cấp cho chúng ta thông tin về nơi có thể sử dụng loại tiền mà vừa chuyển đổi tiền của mình. Bắt đầu với tạo thư mục mới và bắt đầu chạy với npm init, bỏ qua các bước, và cài đặt axois vơi dòng lệnh npm i --save axios. Tạo một file mới currency-converter.js Đầu tiên chúng ta khai báo axios: const axios = require('axios');

Hàm đầu tiên - Lấy dữ liệu bất đồng bộ

Chúng ta tạo một function có hai tham số truyền vào là fromCurrency và toCurrency.

const getExchangeRate = async (fromCurrency, toCurrency) => {}

Bây giờ chúng ta cần lấy dữ liệu. Với async / await, chúng ta có thể gán dữ liệu trực tiếp cho một biến; đừng quên đăng ký và nhập khóa truy cập chính xác của bạn.

const getExchangeRate = async (fromCurrency, toCurrency) => {
  const response = await axios.get('http://data.fixer.io/api/latest?    access_key=[yourAccessKey]&format=1');
}

dữ liệu trả về sẽ dưới dạng response.data.rates nên có thể gán biến cho kết quả trả về:

const rate = response.data.rates;

Vì mọi thứ đang được chuyển đổi từ đồng euro, bên dưới, chúng tôi sẽ tạo ra một biến có tên là euro sẽ bằng 1 / đơn vị tiền tệ mà chúng tôi muốn chuyển đổi từ:

const euro = 1 / rate[fromCurrency];

Cuối cùng, để có được tỷ giá hối đoái, chúng tôi có thể nhân euro với loại tiền mà chúng tôi muốn chuyển đổi thành:

const exchangeRate = euro * rate[toCurrency];

Cuối cùng, hàm sẽ trông giống như thế này:

const getExchangeRate = async (fromCurrency, toCurrency) => {
  const response = await axios.get('http://data.fixer.io/api/latest?    access_key=[yourAccessKey]&format=1');
  const euro = 1 / rate[fromCurrency];
   const exchangeRate = euro * rate[toCurrency];
}

Hàm thứ hai - nhận giá trị quốc gia không đồng bộ

Chúng tôi sẽ tạo ra một hàm không đồng bộ sẽ lấy moneyCode làm đối số:

const getCountries = async (currencyCode) => {}

Như chúng ta đã thấy trước đây, chúng ta sẽ tìm nạp dữ liệu và gán nó cho một biến:

const response = await axios.get(`https://restcountries.eu/rest/v2/currency/${currencyCode}`);

giá trị trả về mảng giá trị name

return response.data.map(country => country.name);

cuối cùng hàm sẽ trông giống như sau:

const getCountries = async (currencyCode) => {
    const response = await axios.get(`https://restcountries.eu/rest/v2/currency/${currencyCode}`);
    return response.data.map(country => country.name);
}

Hàm thứ ba

Chúng ta tạo hàm gồm 3 tham số truyền vào fromCurrency, toCurrency, và amount

const convert = async (fromCurrency, toCurrency, amount) => {}

Đầu tiên chúng ta get currency data:

const exchangeRate = await getExchangeRate(fromCurrency, toCurrency);

Tiếp theo là dữ liệu các nước:

const countries = await getCountries(toCurrency);

Tiếp đến là chuyển đổi giá trị:

const convertedAmount = (amount * exchangeRate).toFixed(2);

Cuối cùng kết quả trả về:

return `${amount} ${fromCurrency} is worth ${convertedAmount} ${toCurrency}. You can spend these in the following countries: ${countries}`;

Tất cả kết hợp lại sẽ trông như thế này:

const convert = async (fromCurrency, toCurrency, amount) => {
    const exchangeRate = await getExchangeRate(fromCurrency, toCurrency);
    const countries = await getCountries(toCurrency);
    const convertedAmount = (amount * exchangeRate).toFixed(2);
    return `${amount} ${fromCurrency} is worth ${convertedAmount} ${toCurrency}. You can spend these in the following countries: ${countries}
}

Thêm try/catch để xử lý lỗi cho hàm đầu tiên

const getExchangeRate = async (fromCurrency, toCurrency) => {
  try {
    const response = await       axios.get('http://data.fixer.io/api/latest?access_key=f68b13604ac8e570a00f7d8fe7f25e1b&format=1');
    const rate = response.data.rates;
    const euro = 1 / rate[fromCurrency];
    const exchangeRate = euro * rate[toCurrency];
    return exchangeRate;
  } catch (error) {
    throw new Error(`Unable to get currency ${fromCurrency} and  ${toCurrency}`);
  }
}

Tương tự với hàm thứ hai:

const getCountries = async (currencyCode) => {
  try {
    const response = await axios.get(`https://restcountries.eu/rest/v2/currency/${currencyCode}`);
return response.data.map(country => country.name);
  } catch (error) {
    throw new Error(`Unable to get countries that use ${currencyCode}`);
  }
};

Cuối cùng là gọi function

convertCurrency('USD', 'HRK', 20)
  .then((message) => {
    console.log(message);
  }).catch((error) => {
    console.log(error.message);
  });

Trên đây là một ví dụ rất đơn giản về sử dụng async/await trong thực tế Tham khảo: https://medium.freecodecamp.org/how-to-master-async-await-with-this-real-world-example-19107e7558ad