Bàn về async/await trong vòng lặp javascript

 


Lâu nay mình đang phải làm một dự án sdk javascript nên khá đau đầu với cái bất đồng bộ trong vòng lặp của  javascript.Để tránh quên nên mình viết lên đây cho đỡ quên.Bài viết này mình chỉ viết về một số ví dụ sử dụng async/await cho dễ hiểu nhé.

1. Chuẩn bị cho ví dụ sắp tới

Giả sử chúng ta có một giỏ trái cây và số lượng của từng trái cây trong giỏ

 const fruitBasket = {  
  apple: 27,  
  grape: 0,  
  pear: 14  
 } 
Bây giờ mình muốn lấy số lượng hoa quả trong giỏ mình sẽ viết một hàm như sau 
 const getNumFruit = fruit => {  
  return fruitBasket[fruit]  
 }  
 const numApples = getNumFruit('apple')  
 console.log(numApples)  
Giờ giả sử fruitBasket được lấy từ server chứ không phải mình khai báo biến như trên nữa việc lấy dữ liệu sẽ mất một vài giây, mình sẽ giả lập công việc lấy dữ liệu từ server như sau
 const sleep = ms => {  
  return new Promise(resolve => setTimeout(resolve, ms))  
 }  
 const getNumFruit = (s, fruit) => {  
  return sleep(s).then(v => fruitBasket[fruit])  
 }  
 getNumFruit(1000, 'apple')  
  .then(num => console.log(num)) // 27  
Hàm sleep tương ứng với việc lag một vài giây, trong hàm này chúng ta trả về một Promise, các bạn chưa biết Promise là gì thì tham khảo tại đây.Ở hàm getNumFruit mình sửa lại chút tức là sau khi chờ 1s thì mới tiếp tục thực hiện lấy số lượng hoa quả.Sau đó mình gọi hàm getNumFruit như trên ví dụ.

Hoặc bây giờ mình sẽ dùng await để lấy số lượng các loại quả trong giỏ, tuy nhiên việc lấy dữ liệu bị gián đoạn khi lấy táo mất 1s, nhưng lấy nho mất tận 3s rồi lấy lê mất 2s.Tuy nhiên nó vẫn sẽ thực hiện tuần tự lấy được táo rồi mới lấy nho cuối cùng mới lấy lê.
 const control = async () => {  
  console.log('Start')  
  const numApples = await getNumFruit(1000, 'apple')  
  console.log(numApples)  
  const numGrapes = await getNumFruit(3000, 'grape')  
  console.log(numGrapes)  
  const numPears = await getNumFruit(2000, 'pear')  
  console.log(numPears)  
  console.log('End')  
 }  

Từ khóa await chỉ được sử dụng trong hàm async thôi nhé, dưới đây là kết quả

Vậy bây giờ chúng ta thử sử dụng await trong vòng lặp  xem sao nhá.

2. Await trong vòng lặp

Bây giờ mình không muốn lấy một loại trái cây nữa mà mình muốn lấy danh sách loại trái cây trong giỏ
và danh sách loại trái cây đấy như sau:
 const fruitsToGet = ['apple', 'grape', 'pear']  
Trong vòng lặp (for) mình cũng sẽ sử dụng hàm getNumFruit để lấy số lượng các loại quả theo thứ tự nhé.
 const forLoop = async () => {  
  console.log('Start')  
  for (let index = 0; index < fruitsToGet.length; index++) {  
   const fruit = fruitsToGet[index]  
   const numFruit = await getNumFruit(1000,fruit)  
   console.log(numFruit)  
  }  
  console.log('End')  
 }  
Khi sử dụng await mình mong đợi sẽ lấy được số lượng trái cây theo thứ tự theo danh sách và kết quả như sau

ồ nó hoạt động tốt kìa , await hoạt động tốt trong các vòng lặp kiểu truyền thống như for, while, for-of .Tuy nhiên với các vòng lặp có callback như forEach, map, filter, reduce thì thế nào nhỉ.Tiếp tục thử nghiệm với các loại loop có callback nhé.

3.Await trong forEach

Bây giờ mình sẽ thử làm tương tự như ví dụ trên nhưng khác là thay vì dùng for thì mình sẽ thử dùng forEach.
 const forEachLoop = () => {  
  console.log('Start')  
  fruitsToGet.forEach(async fruit => {  
   const numFruit = await getNumFruit(1000, fruit)  
   console.log(numFruit)  
  })  
  console.log('End')  
 }  
Chắc các bạn hi vọng nó sẽ trả về kết quả như thế này.
 'Start'  
 '27'  
 '0'  
 '14'  
 'End'  
Nhưng không, kết quả lại không mong đợi như mình muốn mà kết quả như sau

Sở dĩ có việc này là do forEach không nhận biết được promise, forEach không hỗ trợ async và await .Vì vậy chúng ta không thể sử dụng await trong forEach.

Nhận xét

Bài đăng phổ biến từ blog này

Cài đặt SSL cho website sử dụng certbot

Xây dựng một hệ thống comment real-time hoặc chat đơn giản sử dụng Pusher

CÁC BÀI TẬP SQL CƠ BẢN - PART 1

Xây dựng một hệ thống tracking hành vi người dùng (phần 1)

Xây dựng một hệ thống tracking hành vi người dùng (phần 2)

Enterprise architecture trên 1 tờ A4

Web caching (P2)

Web caching (P1)

Cài đặt môi trường để code website Rails