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

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.allPromise.race. Nay lại thêm hai method mới đó là Promise.anyPromise.allSettled

Nó có rối hơn không?, nó có giúp cho chúng ta thêm những gì? Bài viết này sẽ cố gắng giúp các devjs hiểu hơn về hai method sắp ra mắt  What’s new in JavaScript (Google I/O ’19)

Chắc không cần phải giới thiệu nhiều về Promise.all Promise.race nữa phải không? Bởi vì trong blog này cũng đã nói rất rất nhiều về Promise và khi nào cần sử dụng chúng. 

Nếu bạn nào chưa đọc và có thể mới biết đến blog này thì có thể đọc những bài viết về Promise (Tìm hiểu về Promise? Promise giúp devjs hoàn thiện thế nào?) 

Còn nếu các bạn muốn tìm hiểu thêm thì có thể tham khảo hơn nhiều tại đây. 

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

Promise State

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 

Đọc thêm về States and Fates. 

Sự khác nhau giữa các method 

🔅 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