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

Nội dung bài viết

Video học lập trình mỗi ngày

Đối với promise.all() thì chúng ta đã biết và sử dụng rất nhiều trong nhiều tình huống đã được bổ sung ở những bài trước kia. Nhưng bạn có biết ngoài promise.all() ra thì chúng ta vẫn còn nhiều tính năng chưa dùng đến của Promise trong es6 hay không? Nếu bạn cảm thấy hoang mang vì tại sao Promise lại cung cấp nhiều tính năng đến vậy? Thì trong bài viết này chúng ta sẽ tìm hiểu thêm những method như Promise.race(), Promise.any() và Promise.allSettled.


Các bạn nhớ rằng callbacks, rồi đến promise, và hiện tại đang là async/await. Đừng nên lẫn lộn, rồi đi tìm những câu trả lời không cần thiết. Thật sự là cách sử dụng async/await rất khác với promise. Và cách trả về cũng khác luôn.
Hằng ngày chúng ta vẫn thường đang sử dụng hai method Promise.allPromise.race. Nay lại thêm hai methods  mới đó là Promise.anyPromise.allSettled. Vậy hai phương thức này sẽ giúp cho developers giải quyết hay làm được gì giúp chúng ta?

Xem thêm: Tổng hợp những bài viết đi từ callbacks, promise tới async await trong ES6

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 return về một promise được resolved khi tất cả các Promise đã cho đã được resolved hoặc 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' ]

Xem thêm: Tổng hợp những tính năng từ ES6 tới ES11

🚀 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.


Update: Promise.allSettled đã chính thức phát hành ở ES2020.


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

Có thể bạn đã bị missing