de Max Belsky

Diferența reală între captură vs onRejected

Cele mai populare articole descriu diferența dintre catch și onRejected într-un fragment de cod ca acesta:

const getPromise = () => new Promise((resolve, reject) => {  Math.round(Math.random()) ?     resolve('resolve #1') :     reject('reject #1')})
getPromise().then(result => {  throw new Error('reject #2')}, error => {  // Handles only 'reject #1'})
getPromise().then(result => {  throw new Error('reject #2')})  .catch(error => {    // Handles both 'reject #1',     // and 'reject #2'  }))

onRejected nu gestionează niciodată promisiunile respinse de la același lucru .then(onFulfilled) callback și .catch ia ambele. Cu toate acestea, pe lângă diferența de comportament, mai există o nuanță. Este vorba despre cum vor fi traduse aceste moduri microtaskuri și cum vor fi puse în coadă.
Să vedem un exemplu al diferenței.

Promisiunea.rasa

Există o sarcină – scrieți Promise.race polifund. Folosim un model comun în ambele funcții pentru a face față resolved promisiuni și diferite instrumente de gestionat rejected promisiuni.

const promiseRaceOnRejected = (promises = []) => {  return new Promise((resolve, reject) => {    promises.forEach(promise => {      promise.then(        result => resolve(result),        error => reject(error)      )    })  })}
const promiseRaceCatch = (promises = []) => {  return new Promise((resolve, reject) => {    promises.forEach(promise => {      promise.then(result => resolve(result))        .catch(error => reject(error))    })  })}

Încercați câteva teste pentru a vă asigura că ambele soluții funcționează bine:

// A helper function to create a delayed promiseconst getPromise = (resolveMs, rejectMs) => {  return new Promise((resolve, reject) => {    if ('number' === typeof rejectMs) {      setTimeout(() => reject(rejectMs), rejectMs)    }
    if ('number' === typeof resolveMs) {      setTimeout(() => resolve(resolveMs), resolveMs)    }  })}
const testRaces = async () => {  const r1 = await promiseRaceOnRejected([    getPromise(0),     getPromise(5)  ])  // 0
const r2 = await promiseRaceCatch([    getPromise(0),     getPromise(5)  ])  // 0
const r3 = await promiseRaceOnRejected([    getPromise(5),     getPromise(null, 2)  ])    .catch(e => e)  // 2
const r4 = await promiseRaceCatch([    getPromise(5),     getPromise(null, 2)  ])    .catch(e => e)  // 2}
testRaces()

După cum puteți vedea, ambele poliumplute funcționează conform așteptărilor. Argumente ordine și rejected promisiunile variației de manipulare nu contează. Până când îl încercăm cu următorul set de teste:

ad-banner
const r5 = await promiseRaceOnRejected([    Promise.resolve('Resolve'),     Promise.reject('Reject')  ])  // Resolve
const r6 = await promiseRaceCatch([    Promise.resolve('Resolve'),     Promise.reject('Reject')  ])  // Resolve
const r7 = await promiseRaceOnRejected([    Promise.reject('Reject'),     Promise.resolve('Resolve')  ])    .catch(e => e)  // Reject
const r8 = await promiseRaceCatch([    Promise.reject('Reject'),     Promise.resolve('Resolve')  ])    .catch(e => e)  // ???

A cincea, a șasea și a șaptea cursă returnează valorile așteptate. Dar optulea? In loc de Reject se întoarce Resolve și nu este un bug.

Coada de microtaskuri

În funcție de rezultatul postului, o promisiune în așteptare își schimbă starea în resolved sau rejected. Mediul JS pune această promisiune într-o coadă de microtaskuri. Așa cum a fost descris în ECMA 2015 specificație, această coadă funcționează de FIFO principiu – primul intrat, primul ieșit. Pe această bază, să trecem în revistă cazul celei de-a opta curse.

Diferenta reala intre captura si onRejected
Prima bifă a cozii

La începutul cursei, avem deja două promisiuni la coadă, iar respinsul este primul. .then fără un al doilea argument nu poate face față unei promisiuni respinse, așa că pune promisiunea din nou în coadă. Și în loc să tratezi această promisiune cu .catch, mediul JS trece la p2 deoarece are priorități mai mari în coadă.

1611546904 243 Diferenta reala intre captura si onRejected
A doua bifă a cozii

La următoarea bifă .then mânere p2 iar cursa se termină cu Resolve rezultat.

Data viitoare când alegeți între captori și manipulatori on-respecși, amintiți-vă nu numai promisiunile respinse pe care le prind, ci și despre diferența de așteptare!