Dados os exemplos de código abaixo, há alguma diferença no comportamento e, em caso afirmativo, quais são essas diferenças?
return await promise
async function delay1Second() {
return (await delay(1000));
}
return promise
async function delay1Second() {
return delay(1000);
}
Pelo que entendi, o primeiro teria tratamento de erros dentro da função assíncrona, e os erros surgiam na promessa da função assíncrona. No entanto, o segundo exigiria um tique a menos. Isso está correto?
Este snippet é apenas uma função comum para retornar uma promessa para referência.
function delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
javascript
async-await
PitaJ
fonte
fonte
async
de sua segunda (return promise
) amostra.promise.then(() => nestedPromise)
achataria e "seguiria" onestedPromise
. Interessante como é diferente de tarefas aninhadas em C # onde teríamos que fazê-Unwrap
lo. Em uma nota lateral, parece queawait somePromise
chamaPromise.resolve(somePromise).then
, em vez de apenassomePromise.then
, com algumas diferenças semânticas interessantes.Respostas:
Na maioria das vezes, não há diferença observável entre
return
ereturn await
. Ambas as versões dedelay1Second
têm exatamente o mesmo comportamento observável (mas dependendo da implementação, areturn await
versão pode usar um pouco mais de memória porque umPromise
objeto intermediário pode ser criado).No entanto, como @PitaJ apontou, há um caso em que há uma diferença: se o
return
oureturn await
estiver aninhado em um blocotry
-catch
. Considere este exemploNa primeira versão, a função assíncrona aguarda a promessa rejeitada antes de retornar seu resultado, o que faz com que a rejeição se transforme em uma exceção e a
catch
cláusula seja alcançada; a função, portanto, retornará uma promessa resolvida para a string "Salvo!".A segunda versão da função, no entanto, retorna a promessa rejeitada diretamente, sem aguardá-la na função assíncrona , o que significa que o
catch
caso não é chamado e o chamador obtém a rejeição.fonte
return new Promise(function(resolve, reject) { })
dentro de umfor...of
loop e, em seguida, chamarresolve()
dentro do loop após umpipe()
não interrompe a execução do programa até que o pipe seja concluído, conforme desejado, mas o uso oawait new Promise(...)
faz. é a última sintaxe válida / correta? é uma 'abreviação' parareturn await new Promise(...)
? você poderia me ajudar a entender por que o último funciona e o primeiro não? para o contexto, o cenário está emsolution 02
de esta respostaComo outras respostas mencionadas, é provável que haja um pequeno benefício de desempenho ao permitir que a promessa borbulhe ao devolvê-la diretamente - simplesmente porque você não precisa esperar o resultado primeiro e depois envolvê-lo com outra promessa novamente. No entanto, ninguém falou sobre a otimização da chamada final ainda.
A otimização da chamada final , ou “chamadas finais adequadas” , é uma técnica que o interpretador usa para otimizar a pilha de chamadas. Atualmente, poucos runtimes suportam ainda - embora seja tecnicamente parte do ES6 Standard - mas é possível que o suporte seja adicionado no futuro, então você pode se preparar para isso escrevendo um bom código no presente.
Resumindo, o TCO (ou PTC) otimiza a pilha de chamadas ao não abrir um novo quadro para uma função que é retornada diretamente por outra função. Em vez disso, ele reutiliza o mesmo quadro.
Como
delay()
é retornado diretamente pordelay1Second()
, os tempos de execução que suportam PTC abrirão primeiro um quadro paradelay1Second()
(a função externa), mas, em vez de abrir outro quadro paradelay()
(a função interna), ele apenas reutilizará o mesmo quadro que foi aberto para a função externa. Isso otimiza a pilha porque pode evitar um estouro de pilha (hehe) com funções recursivas muito grandes, por exemplofibonacci(5e+25)
,. Essencialmente, torna-se um loop, que é muito mais rápido.PTC só é habilitado quando a função interna é retornada diretamente . Não é usado quando o resultado da função é alterado antes de ser retornado, por exemplo, se você tinha
return (delay(1000) || null)
, oureturn await delay(1000)
.Mas, como eu disse, a maioria dos tempos de execução e navegadores ainda não oferecem suporte a PTC, então provavelmente não fará uma grande diferença agora, mas não faria mal ao preparar o seu código para o futuro.
Leia mais nesta pergunta: Node.js: existem otimizações para chamadas finais em funções assíncronas?
fonte
Esta é uma pergunta difícil de responder, porque depende na prática de como seu transpiler (provavelmente
babel
) realmente renderizaasync/await
. As coisas que são claras de qualquer maneira:Ambas as implementações devem se comportar da mesma forma, embora a primeira implementação possa ter uma a menos
Promise
na cadeia.Especialmente se você descartar o desnecessário
await
, a segunda versão não exigiria nenhum código extra do transpiler, enquanto a primeira requer.Portanto, de uma perspectiva de desempenho de código e depuração, a segunda versão é preferível, embora apenas ligeiramente, enquanto a primeira versão tem um pequeno benefício de legibilidade, na medida em que indica claramente que retorna uma promessa.
fonte
undefined
) e o segundo retorna aPromise
.async/await
- acho muito mais difícil raciocinar a respeito. @PitaJ está correto, ambas as funções retornam uma promessa.try-catch
? Noreturn promise
caso, nenhumrejection
seria pego, correto, enquanto, noreturn await promise
caso, seria, certo?await
cada um desses em algum site de chamada, o resultado será muito diferente.deixo aqui algum código prático para você entender a diferença
a função "x" é apenas uma função assíncrona do que outra fucn se for deletar o retorno imprimir "mais código ..."
a variável x é apenas uma função assíncrona que por sua vez tem outra função assíncrona, no principal do código invocamos uma espera para chamar a função da variável x, quando completa segue a sequência do código, isso seria normal para "async / await", mas dentro da função x há outra função assíncrona, e esta retorna uma promessa ou retorna uma "promessa" que ficará dentro da função x, esquecendo o código principal, ou seja, não imprimirá o "console.log (" mais código .. "), por outro lado se colocarmos" esperar "ele irá aguardar cada função que for concluída e finalmente seguirá a sequência normal do código principal.
abaixo do "console.log (" finalizado 1 "exclua o" retorno ", você verá o comportamento.
fonte
Aqui está um exemplo de texto datilografado que você pode executar e se convencer de que precisa de "retorno e espera"
fonte
Diferença perceptível: a rejeição da promessa é tratada em lugares diferentes
return somePromise
irá passar somePromise para o local da chamada eawait
algumaPromise para liquidar no local da chamada (se houver). Portanto, se alguma Promessa for rejeitada, ela não será tratada pelo bloco catch local, mas pelo bloco catch do site de chamada.return await somePromise
irá primeiro esperar alguma promessa para se estabelecer localmente. Portanto, o valor ou Exceção será primeiro tratado localmente. => Bloco local catch será executado sesomePromise
for rejeitado.Motivo:
return await Promise
espera localmente e fora,return Promise
espera apenas foraEtapas detalhadas:
promessa de retorno
delay1Second()
;delay1Second()
, a funçãodelay(1000)
retorna uma promessa imediatamente com[[PromiseStatus]]: 'pending
. Vamos encerrardelayPromise
.Promise.resolve()
( Origem ). Pordelay1Second
ser uma função assíncrona, temos:Promise.resolve(delayPromise)
retornadelayPromise
sem fazer nada porque a entrada já é uma promessa (consulte MDN Promise.resolve ):await
espera até que odelayPromise
seja liquidado.delayPromise
é cumprido com PromiseValue = 1:delayPromise
é rejeitado:retorno e espera promessa
delay1Second()
;delay1Second()
, a funçãodelay(1000)
retorna uma promessa imediatamente com[[PromiseStatus]]: 'pending
. Vamos encerrardelayPromise
.delayPromise
ser resolvida.delayPromise
é cumprido com PromiseValue = 1:delayPromise
é rejeitado:Glossário:
Promise.[[PromiseStatus]]
mudanças depending
pararesolved
ourejected
fonte