Promise.race vs. Promise.any And Promise.all vs. Promise.allSettled

Trong bài viết tôi và devjs sẽ tìm hiểu về những method Promise.all, Promise.race, Promise.any và Promise.allSettled. Trong series promise javascript.

Thấy tiêu đề các bạn nghĩ đến gì trong khi hằng ngày chúng ta vẫn sử dụng hai method Promise.all và Promise.race. Nay lại thêm hai method mới đó là Promise.any và Promise.allSettled.


1 - Promise JavaScript là gì?

Promise là một cơ chế trong JavaScript giúp bạn thực thi các tác vụ bất đồng bộ mà không rơi vào callback hell hay pyramid of doom, là tình trạng các hàm callback lồng vào nhau ở quá nhiều tầng.

Nhưng để tôi nói qua một chút về promise state javascript. Giờ đây sẽ có 4 state 

Promise state javascript 

  • Fulfilled – Khi promise resolved successfully. 
  • Rejected – Khi promise failed. 
  • Pending – Khi promise đang chờ trả về Fulfilled or Rejected. 
  • Settled – Thuật ngữ này dùng để mô tả cho method mới có lẽ sắp ra mắt

2 - Ví dụ về promise javascript

Sự khác nhau giữa các all promise javascript

🔅 Promise.all vs. Promise.allSettled 

Promise.all duyệt hết nhưng return ngay khi một Promise nào đó return về Rejected 

Promise.allSettled duyệt hết và return ngay cả khi một Promise nào đó return về Rejected 

🔅 Promise.race vs. Promise.any 

Promise.race return ngay khi một Promise đầu tiên nào đó return về bất kể (Rejected hay Fulfilled)

Promise.any return ngay khi một Promise có state Fulfilled bất kể có nhiều Promise sẽ return về Rejected 

Để hiểu rõ hơn chúng ta sẽ đi tìm hiểu kỹ hơn thông qua một vài ví dụ sau: 

🚀 Promise.all

const promisesWithoutReject = [
  Promise.resolve('🍎 #1'),
  '🍎 #2',
  new Promise((resolve, reject) => setTimeout(resolve, 100, '🍎 #3'))
]

Promise.all(promisesWithoutReject)
  .then(apples => console.log(`We can sell all these good apples`, apples))


const promisesWithOneReject = [
  Promise.resolve('🍎 #1'),
  '🍎 #2',
  new Promise((_, reject) => setTimeout(reject, 100, 'Bad 🍏'))
]

Promise.all(promisesWithOneReject)
  .then(console.log)
  .catch(badApple => 
    console.error(`Threw out all apples because of this`, badApple))
    

Output

We can sell all these good apples [ '🍎 #1', '🍎 #2', '🍎 #3' ]
Threw out all apples because of this Bad 🍏

🚀 Promise.allSettled

const allRejectedPromises = [
  Promise.reject('🍏 #1'),
  Promise.reject('🍏 #2'),
  Promise.reject('🍏 #3'),
]

Promise.allSettled(allRejectedPromises)
  .then(badApples => 
    console.log(`We can't sell any of these apples...`, badApples))
  .catch(error => console.error('This should never occur'))


const promisesWithoutReject = [
  Promise.resolve('🍎 #1'),
  '🍎 #2',
  new Promise((resolve, reject) => setTimeout(resolve, 100, '🍎 #3'))
]

Promise.allSettled(promisesWithoutReject)
  .then(apples => console.log(`We can sell all these good apples`, apples.map(_=>_.value)))


const promisesWithOneReject = [
  Promise.resolve('🍎 #1'),
  new Promise((_, reject) => setTimeout(reject, 10, '🍏 #2')),
  '🍎 #3',
  new Promise((_, reject) => setTimeout(reject, 100, '🍏 #4'))
]

const extractApples = apples => apples.map(_ => _.value)
Promise.allSettled(promisesWithOneReject)
  .then(apples => {
    const badApples = apples.filter(apple => apple.status === 'rejected').map(_ => _.reason)
    const goodApples = apples.filter(apple => apple.status === 'fulfilled').map(_ => _.value)

    console.log(`Let's throw out`, badApples, `and sell the rest`, goodApples)
  })
  
  

Output

We can't sell any of these apples... 
[ { status: 'rejected', reason: '🍏 #1' },
  { status: 'rejected', reason: '🍏 #2' },
  { status: 'rejected', reason: '🍏 #3' } ]
We can sell all these good apples [ '🍎 #1', '🍎 #2', '🍎 #3' ]
Let's throw out [ '🍏 #2', '🍏 #4' ] and sell the rest [ '🍎 #1', '🍎 #3' ]

🚀 Promise.race

const promiseWillFulfill = [
  new Promise((resolve, reject) => setTimeout(reject, 250, '😈')),
  new Promise((resolve, reject) => setTimeout(resolve, 150, '😇')),
  new Promise((resolve, reject) => setTimeout(resolve, 1, '😇')),
]
Promise.race(promiseWillFulfill)
  .then(value => console.log(`The humanity survives "${value}"`))
  .catch(error => console.log(`Won't be called as 😇 will win the race`))



const promiseWillReject = [
  new Promise((resolve, reject) => setTimeout(resolve, 250, '😇')),
  new Promise((resolve, reject) => setTimeout(reject, 1, '😈')),
  new Promise((resolve, reject) => setTimeout(resolve, 250, '😇')),
]
Promise.race(promiseWillReject)
  .then(value => console.log(`This won't be called...="${value}"`))
  .catch(error => console.log(`The humanity is doomed...="${error}"`))


const promisesWithOUTReject = [
  new Promise(resolve => setTimeout(resolve, 350, 'one')),
  new Promise(resolve => setTimeout(resolve, 250, 'two')),
  new Promise(resolve => setTimeout(resolve, 150, 'three')),
]
Promise.race(promisesWithOUTReject)
  .then(value => console.log(`Promise without reject="${value}"`))

Output

The humanity survives "😇"
The humanity is doomed...="😈"
Promise without reject="three"

🚀 Promise.any

// Example #1
Promise.any([
    Promise.reject('✗'),
    Promise.reject('✗'),
    Promise.resolve('✓'),
    Promise.reject('✗'),
]).then(function(value) {
    console.log(`You win at life`, value)
});

// Example #2
// You get the first fulfilled value
Promise.any([
    new Promise((_, reject) => setTimeout(reject, 10, '✗')),
    new Promise((_, reject) => setTimeout(reject, 20, '✗')),
    new Promise((_, reject) => setTimeout(reject, 30, '✗')),
    new Promise(resolve => setTimeout(resolve, 100, 'I got a job!')),
    new Promise(resolve => setTimeout(resolve, 1000, 'I could have gotten a better job!')),
]).then(function(value) {
    console.log(value)
});

// Example #3
// You get all rejection reasons 
Promise.any([
    Promise.reject('✗'),
    Promise.reject('✗'),
]).catch(function(reasons) {
    console.log(`Didn't get any offers...`, reasons)
});

Output

// Note that the result of Example #3 is printed first because of `setTimeout` in example #2

// Result of Example #1
You win at life ✓
// Result of Example #3
Didn't get any offers... [ '✗', '✗' ]
// Result of Example #2
I got a job!

👋 Kết luận 

Mặc dầu hai method mới Promise.anyPromise.allSettled vẫn chưa hợp lệ trên các trình duyệt nhưng qua dự đoán của các nhà phát triển JS thì chúng ta có thể yên tâm hơn cho việc xử lý bất đồng bộ trên ứng dụng của mình.
Các bạn nào đam mê hơn thì có thể xem những tính năng chuẩn bị ra mắt tại link này nhé. What’s new in JavaScript (Google I/O ’19) 

Tham khảo bài viết gốc tại đây