O return
objetivo é encerrar a execução da função após a rejeição e impedir a execução do código após ela.
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);
});
}
Nesse caso, impede a resolve(numerator / denominator);
execução, o que não é estritamente necessário. No entanto, ainda é preferível encerrar a execução para evitar uma possível interceptação no futuro. Além disso, é uma boa prática evitar a execução desnecessária de código.
fundo
Uma promessa pode estar em um dos três estados:
- pendente - estado inicial. De pendente, podemos passar para um dos outros estados
- cumprida - operação bem sucedida
- rejeitado - operação com falha
Quando uma promessa é cumprida ou rejeitada, ela permanece neste estado indefinidamente (liquidada). Portanto, rejeitar uma promessa cumprida ou cumprir uma promessa rejeitada não terá efeito.
Este trecho de exemplo mostra que, embora a promessa tenha sido cumprida após ser rejeitada, ela permaneceu rejeitada.
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));
Então, por que precisamos retornar?
Embora não possamos alterar um estado de promessa estabelecida, rejeitar ou resolver não interromperá a execução do restante da função. A função pode conter código que criará resultados confusos. Por exemplo:
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));
Mesmo que a função não contenha esse código no momento, isso cria uma possível armadilha futura. Um refatorador futuro pode ignorar o fato de que o código ainda é executado após a promessa ser rejeitada e será difícil depurar.
Parando a execução após resolver / rejeitar:
Esse é o material padrão do fluxo de controle JS.
- Retornar após o
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));
- Retorno com
resolve
/ reject
- como o valor de retorno do retorno de chamada é ignorado, podemos salvar uma linha retornando a instrução rejeitar / resolver:
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 um bloco 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));
Prefiro usar uma das return
opções, pois o código é mais plano.