sincronas promesas funciones javascript promise

funciones - Promesas de JavaScript: rechazar frente a tirar



funciones sincronas javascript (5)

No hay ninguna ventaja de usar uno frente al otro, pero hay un caso específico en el que el throw no funcionará. Sin embargo, esos casos se pueden arreglar.

Cada vez que esté dentro de una devolución de llamada de promesa, puede usar throw . Sin embargo, si está en cualquier otra devolución de llamada asincrónica, debe usar el reject .

Por ejemplo, esto no activará la captura:

new Promise(function() { setTimeout(function() { throw ''or nah''; // return Promise.reject(''or nah''); also won''t work }, 1000); }).catch(function(e) { console.log(e); // doesn''t happen });

En cambio, te queda una promesa no resuelta y una excepción no alcanzada. Ese es un caso en el que desearía utilizar reject . Sin embargo, puede solucionar esto prometiendo el tiempo de espera:

function timeout(duration) { // Thanks joews return new Promise(function(resolve) { setTimeout(resolve, duration); }); } timeout(1000).then(function() { throw ''worky!''; // return Promise.reject(''worky''); also works }).catch(function(e) { console.log(e); // ''worky!'' });

He leído varios artículos sobre este tema, pero aún no me queda claro si hay una diferencia entre Promise.reject y arrojar un error. Por ejemplo,

Usando Promise.reject

return asyncIsPermitted() .then(function(result) { if (result === true) { return true; } else { return Promise.reject(new PermissionDenied()); } });

Usando tiro

return asyncIsPermitted() .then(function(result) { if (result === true) { return true; } else { throw new PermissionDenied(); } });

Prefiero usar throw simplemente porque es más corto, pero me preguntaba si hay alguna ventaja de uno sobre el otro.


Otro hecho importante es que reject() NO termina el flujo de control como lo hace una declaración de return . En contraste, el throw termina el flujo de control.

Ejemplo:

new Promise((resolve, reject) => { throw "err"; console.log("NEVER REACHED"); }) .then(() => console.log("RESOLVED")) .catch(() => console.log("REJECTED"));

vs

new Promise((resolve, reject) => { reject(); // resolve() behaves similarly console.log("ALWAYS REACHED"); // "REJECTED" will print AFTER this }) .then(() => console.log("RESOLVED")) .catch(() => console.log("REJECTED"));


Sí, la mayor diferencia es que el rechazo es una función de devolución de llamada que se lleva a cabo después de que se rechaza la promesa, mientras que throw no se puede usar de forma asincrónica. Si elige usar el rechazo, su código continuará ejecutándose normalmente de forma asincrónica, mientras que throw priorizará completar la función de resolución (esta función se ejecutará inmediatamente).

Un ejemplo que he visto que me ayudó a aclarar el problema fue que podía establecer una función de tiempo de espera con rechazo, por ejemplo:

new Promise(_, reject) { setTimeout(reject, 3000); });

Lo anterior no podría ser posible escribir con tiro.

En su pequeño ejemplo, la diferencia es indistinguible, pero cuando se trata de un concepto asincrónico más complicado, la diferencia entre los dos puede ser drástica.


Un ejemplo para probar. Simplemente cambie isVersionThrow a falso para usar rechazar en lugar de lanzar.

const isVersionThrow = true class TestClass { async testFunction () { if (isVersionThrow) { console.log(''Throw version'') throw new Error(''Fail!'') } else { console.log(''Reject version'') return new Promise((resolve, reject) => { reject(new Error(''Fail!'')) }) } } } const test = async () => { const test = new TestClass() try { var response = await test.testFunction() return response } catch (error) { console.log(''ERROR RETURNED'') throw error } } test() .then(result => { console.log(''result: '' + result) }) .catch(error => { console.log(''error: '' + error) })


TLDR: una función es difícil de usar cuando a veces devuelve una promesa y a veces arroja una excepción. Al escribir una función asíncrona, prefiera señalar la falla devolviendo una promesa rechazada

Su ejemplo particular ofusca algunas distinciones importantes entre ellos:

Debido a que está manejando errores dentro de una cadena de promesa, las excepciones lanzadas se convierten automáticamente en promesas rechazadas. Esto puede explicar por qué parecen ser intercambiables, no lo son.

Considere la siguiente situación:

checkCredentials = () => { let idToken = localStorage.getItem(''some token''); if ( idToken ) { return fetch(`https://someValidateEndpoint`, { headers: { Authorization: `Bearer ${idToken}` } }) } else { throw new Error(''No Token Found In Local Storage'') } }

Esto sería un antipatrón porque necesitaría admitir casos de error de sincronización y asíncrono. Podría parecerse a algo como:

try { function onFulfilled() { ... do the rest of your logic } function onRejected() { // handle async failure - like network timeout } checkCredentials(x).then(onFulfilled, onRejected); } catch (e) { // Error(''No Token Found In Local Storage'') // handle synchronous failure }

No es bueno y aquí es exactamente donde Promise.reject (disponible en el ámbito global) viene al rescate y se diferencia efectivamente del throw . El refactor ahora se convierte en:

checkCredentials = () => { let idToken = localStorage.getItem(''some_token''); if (!idToken) { return Promise.reject(''No Token Found In Local Storage'') } return fetch(`https://someValidateEndpoint`, { headers: { Authorization: `Bearer ${idToken}` } }) }

Esto ahora le permite usar solo un catch() para fallas en la red y la verificación de errores síncronos por falta de tokens:

checkCredentials() .catch((error) => if ( error == ''No Token'' ) { // do no token modal } else if ( error === 400 ) { // do not authorized modal. etc. }