El return
propósito es terminar la ejecución de la función después del rechazo y evitar la ejecución del código después de ella.
function divide(numerator, denominator) {
return new Promise((resolve, reject) => {
if (denominator === 0) {
reject("Cannot divide by 0");
return; // The function execution ends here
}
resolve(numerator / denominator);
});
}
En este caso, evita resolve(numerator / denominator);
que se ejecute, lo cual no es estrictamente necesario. Sin embargo, aún es preferible terminar la ejecución para evitar una posible trampa en el futuro. Además, es una buena práctica evitar que se ejecute código innecesariamente.
Antecedentes
Una promesa puede ser en uno de los 3 estados:
- pendiente - estado inicial. De pendiente podemos pasar a uno de los otros estados
- cumplido - operación exitosa
- rechazado - operación fallida
Cuando una promesa se cumple o se rechaza, permanecerá en este estado indefinidamente (resuelta). Por lo tanto, rechazar una promesa cumplida o cumplir una promesa rechazada no tendrá efecto.
Este fragmento de ejemplo muestra que, aunque la promesa se cumplió después de ser rechazada, se mantuvo rechazada.
function divide(numerator, denominator) {
return new Promise((resolve, reject) => {
if (denominator === 0) {
reject("Cannot divide by 0");
}
resolve(numerator / denominator);
});
}
divide(5,0)
.then((result) => console.log('result: ', result))
.catch((error) => console.log('error: ', error));
Entonces, ¿por qué necesitamos volver?
Aunque no podemos cambiar un estado de promesa establecido, rechazar o resolver no detendrá la ejecución del resto de la función. La función puede contener código que creará resultados confusos. Por ejemplo:
function divide(numerator, denominator) {
return new Promise((resolve, reject) => {
if (denominator === 0) {
reject("Cannot divide by 0");
}
console.log('operation succeeded');
resolve(numerator / denominator);
});
}
divide(5, 0)
.then((result) => console.log('result: ', result))
.catch((error) => console.log('error: ', error));
Incluso si la función no contiene ese código en este momento, esto crea una posible trampa futura. Un futuro refactor podría ignorar el hecho de que el código aún se ejecuta después de que se rechaza la promesa, y será difícil de depurar.
Detener la ejecución después de resolver / rechazar:
Este es el flujo de control estándar de JS.
- Regresar después de
resolve
/ reject
:
function divide(numerator, denominator) {
return new Promise((resolve, reject) => {
if (denominator === 0) {
reject("Cannot divide by 0");
return;
}
console.log('operation succeeded');
resolve(numerator / denominator);
});
}
divide(5, 0)
.then((result) => console.log('result: ', result))
.catch((error) => console.log('error: ', error));
- Regrese con el
resolve
/ reject
- ya que se ignora el valor de retorno de la devolución de llamada, podemos guardar una línea devolviendo la declaración de rechazo / resolución:
function divide(numerator, denominator) {
return new Promise((resolve, reject) => {
if (denominator === 0) {
return reject("Cannot divide by 0");
}
console.log('operation succeeded');
resolve(numerator / denominator);
});
}
divide(5, 0)
.then((result) => console.log('result: ', result))
.catch((error) => console.log('error: ', error));
- Usando un bloque if / else:
function divide(numerator, denominator) {
return new Promise((resolve, reject) => {
if (denominator === 0) {
reject("Cannot divide by 0");
} else {
console.log('operation succeeded');
resolve(numerator / denominator);
}
});
}
divide(5, 0)
.then((result) => console.log('result: ', result))
.catch((error) => console.log('error: ', error));
Prefiero usar una de las return
opciones ya que el código es más plano.