Estou desenvolvendo JavaScript há alguns anos e não entendo nada sobre promessas.
Parece que tudo o que faço é mudar:
api(function(result){
api2(function(result2){
api3(function(result3){
// do work
});
});
});
Para o qual eu poderia usar uma biblioteca como assíncrona, de qualquer maneira, com algo como:
api().then(function(result){
api2().then(function(result2){
api3().then(function(result3){
// do work
});
});
});
Qual é mais código e menos legível. Eu não ganhei nada aqui, de repente também não é magicamente 'plano'. Sem mencionar a necessidade de converter as coisas em promessas.
Então, qual é o grande alarido sobre promessas aqui?
Respostas:
Promessas não são retornos de chamada. Uma promessa representa o resultado futuro de uma operação assíncrona . É claro que, ao escrevê-las como você faz, você obtém pouco benefício. Mas se você as escrever da maneira como elas devem ser usadas, poderá escrever código assíncrono de uma maneira que se assemelhe ao código síncrono e seja muito mais fácil de seguir:
Certamente, não muito menos código, mas muito mais legível.
Mas este não é o fim. Vamos descobrir os verdadeiros benefícios: E se você quisesse verificar algum erro em alguma das etapas? Seria um inferno fazer isso com retornos de chamada, mas com promessas, é um pedaço de bolo:
Praticamente o mesmo que um
try { ... } catch
bloco.Melhor ainda:
E melhor ainda: E se esses 3 chamadas para
api
,api2
,api3
poderia correr simultaneamente (por exemplo, se fossem chamadas AJAX), mas você precisava esperar para os três? Sem promessas, você deve criar algum tipo de contador. Com promessas, usando a notação ES6, é outro pedaço de bolo e bem arrumado:Espero que você veja as promessas sob uma nova luz agora.
fonte
api2
eapi3
? o último.then
seria chamado apenas quando essas operações assíncronas estivessem concluídas?Sim, promessas são retornos de chamada assíncronos. Eles não podem fazer nada que os retornos de chamada não possam fazer, e você enfrenta os mesmos problemas com assincronia e com retornos simples.
No entanto, as promessas são mais do que apenas retornos de chamada. Eles são uma abstração muito poderosa, permitem códigos funcionais mais limpos e melhores com clichê menos propenso a erros.
Promessas são objetos que representam o resultado de uma única computação (assíncrona). Eles resolvem esse resultado apenas uma vez. Existem algumas coisas que isso significa:
Promessas implementam um padrão de observador:
return
um objeto PromiseAs promessas são encadeadas ( monádicas , se você quiser ):
.then()
método É necessário um retorno de chamada para ser chamado com o primeiro resultado e retorna uma promessa para o resultado da promessa que o retorno de chamada retorna.Parece complicado? Hora de um exemplo de código.
O achatamento não ocorre magicamente, mas você pode fazê-lo facilmente. Para o seu exemplo fortemente aninhado, o equivalente (quase) seria
Se ver o código desses métodos ajuda a entender, aqui está uma lib de promessa mais básica em algumas linhas .
A abstração Promise permite uma composição de funções muito melhor. Por exemplo, ao lado de
then
de encadeamento, aall
função cria uma promessa para o resultado combinado de várias promessas de espera paralela.Por último, mas não menos importante, as promessas vêm com o tratamento de erros integrado. O resultado do cálculo pode ser que a promessa seja cumprida com um valor ou seja rejeitada por uma razão. Todas as funções de composição lidam com isso automaticamente e propagam erros em cadeias de promessas, para que você não precise se preocupar com isso explicitamente em todos os lugares - em contraste com uma implementação simples de retorno de chamada. No final, você pode adicionar um retorno de chamada de erro dedicado para todas as exceções ocorridas.
Isso é bastante trivial, na verdade, com boas bibliotecas de promessas, consulte Como converter uma API de retorno de chamada existente em promessas?
fonte
.then(console.log)
, pois console.log depende do contexto do console. Dessa forma, causará um erro de chamada ilegal. Useconsole.log.bind(console)
oux => console.log(x)
para vincular o contexto.console
métodos já estão vinculados. E, é claro, eu apenas disse que os dois ninhos têm exatamente o mesmo comportamento, não que nenhum deles funcione:Além das respostas já estabelecidos, com ES6 seta funções Promises transformar de um pequeno anão azul modestamente brilhando diretamente em uma gigante vermelha. Isso está prestes a entrar em colapso em uma supernova:
Como o oligofren apontou, sem argumentos entre chamadas de API, você não precisa das funções de invólucro anônimo:
E, finalmente, se você deseja atingir um nível supermassivo de buraco negro, podem ser esperadas promessas:
fonte
apiX
métodos, assim como você pode ignorar as funções de seta completamente:api().then(api2).then(api3).then(r3 => console.log(r3))
.Além das respostas impressionantes acima, mais 2 pontos podem ser adicionados:
1. Diferença semântica:
As promessas já podem ser resolvidas após a criação. Isso significa que eles garantem condições e não eventos . Se eles já estiverem resolvidos, a função resolvida passada para ele ainda será chamada.
Por outro lado, os retornos de chamada manipulam eventos. Portanto, se o evento em que você tiver interesse tiver ocorrido antes do registro de retorno, o retorno não será chamado.
2. Inversão de controle
Os retornos de chamada envolvem inversão de controle. Quando você registra uma função de retorno de chamada com qualquer API, o tempo de execução do Javascript armazena a função de retorno de chamada e a chama a partir do loop de eventos quando estiver pronta para ser executada.
Consulte O loop de eventos Javascript para obter uma explicação.
Com Promessas , o controle reside no programa de chamada. O método .then () pode ser chamado a qualquer momento se armazenarmos o objeto de promessa.
fonte
Além das outras respostas, a sintaxe do ES2015 combina perfeitamente com as promessas, reduzindo ainda mais o código padrão:
fonte
Promessas não são retornos de chamada, ambos são idiomas de programação que facilitam a programação assíncrona. O uso de um estilo de programação assíncrono / aguardado, usando corotinas ou geradores que retornam promessas, pode ser considerado um terceiro idioma desse tipo. Uma comparação desses idiomas entre diferentes linguagens de programação (incluindo Javascript) está aqui: https://github.com/KjellSchubert/promise-future-task
fonte
Não, não mesmo.
Retornos de chamada são simplesmente funções em JavaScript chamada que devem ser chamadas e executadas após a conclusão de outra função. Então como isso acontece?
Na verdade, no JavaScript, as funções são consideradas como objetos e, portanto, como todos os outros objetos, até as funções podem ser enviadas como argumentos para outras funções . O caso de uso mais comum e genérico em que se pode pensar é a função setTimeout () em JavaScript.
As promessas nada mais são do que uma abordagem muito mais improvisada de manipulação e estruturação de código assíncrono, em comparação com fazer o mesmo com retornos de chamada.
A promessa recebe dois retornos de chamada na função construtora: resolver e rejeitar. Essas promessas de retorno internas nos fornecem controle refinado sobre o tratamento de erros e casos de sucesso. O retorno de chamada de resolução é usado quando a execução da promessa é realizada com êxito e o retorno de chamada de rejeição é usado para manipular os casos de erro.
fonte
Nenhuma promessa é apenas invólucro nos retornos de chamada
exemplo Você pode usar promessas nativas de javascript com o nó js
fonte
As promessas JavaScript realmente usam funções de retorno de chamada para determinar o que fazer depois que uma promessa foi resolvida ou rejeitada, portanto, ambas não são fundamentalmente diferentes. A principal idéia por trás do Promises é receber retornos de chamada - especialmente retornos aninhados, nos quais você deseja executar uma espécie de ações, mas seria mais legível.
fonte
Visão geral das promessas:
Em JS, podemos envolver operações assíncronas (por exemplo, chamadas de banco de dados, chamadas AJAX) em promessas. Normalmente, queremos executar alguma lógica adicional nos dados recuperados. As promessas de JS têm funções de manipulador que processam o resultado das operações assíncronas. As funções do manipulador podem até ter outras operações assíncronas dentro delas, que podem contar com o valor das operações assíncronas anteriores.
Uma promessa sempre tem um dos três seguintes estados:
Uma promessa pendente pode ser resolvida / preenchida ou rejeitada com um valor. Em seguida, os seguintes métodos manipuladores que recebem retornos de chamada como argumentos são chamados:
Promise.prototype.then()
: Quando a promessa for resolvida, o argumento de retorno de chamada dessa função será chamado.Promise.prototype.catch()
: Quando a promessa é rejeitada, o argumento de retorno de chamada dessa função será chamado.Embora a habilidade dos métodos acima obtenha argumentos de retorno de chamada, eles são muito superiores ao uso apenas de retorno de chamada. Aqui está um exemplo que esclarecerá muito:
Exemplo
then
método é chamado e o valor resolvido é passado como argumento do retorno de chamadacatch
método é chamado e o valor rejeitado é passado como argumentocatch
ethen
retornam promessas, é por isso que podemos encadeá-los. Eles envolvem qualquer valor retornadoPromise.resolve
e qualquer valor jogado (usando athrow
palavra - chave)Promise.reject
. Portanto, qualquer valor retornado é transformado em promessa e, novamente, podemos chamar uma função de manipulador.catch
método lida com todos os erros que ocorreram antes docatch
manipulador.fonte