→ Para obter uma explicação mais geral do comportamento assíncrono com exemplos diferentes, consulte Por que minha variável é inalterada depois que a modifico dentro de uma função? - Referência de código assíncrona
→ Se você já entendeu o problema, pule para as possíveis soluções abaixo.
O problema
O Um em Ajax significa assíncrona . Isso significa que o envio da solicitação (ou melhor, o recebimento da resposta) é retirado do fluxo de execução normal. No seu exemplo, $.ajax
retorna imediatamente e a próxima instrução return result;
,, é executada antes da função que você passou como success
retorno de chamada ser chamada.
Aqui está uma analogia que, esperançosamente, torna mais clara a diferença entre fluxo síncrono e assíncrono:
Síncrono
Imagine que você telefona para um amigo e pede que ele procure algo para você. Embora possa demorar um pouco, você espera no telefone e fica olhando para o espaço, até que seu amigo lhe dê a resposta que você precisava.
O mesmo está acontecendo quando você faz uma chamada de função contendo código "normal":
function findItem() {
var item;
while(item_not_found) {
// search
}
return item;
}
var item = findItem();
// Do something with item
doSomethingElse();
Mesmo que findItem
demore muito tempo para executar, qualquer código que vem depois var item = findItem();
precisa esperar até que a função retorne o resultado.
Assíncrono
Você chama seu amigo novamente pelo mesmo motivo. Mas desta vez você diz a ele que está com pressa e ele deve ligar de volta no seu celular. Você desliga, sai de casa e faz o que planeja fazer. Quando seu amigo ligar de volta, você estará lidando com as informações que ele lhe deu.
É exatamente o que está acontecendo quando você faz uma solicitação do Ajax.
findItem(function(item) {
// Do something with item
});
doSomethingElse();
Em vez de aguardar a resposta, a execução continua imediatamente e a instrução após a execução da chamada do Ajax. Para obter a resposta eventualmente, você fornece uma função a ser chamada assim que a resposta é recebida, um retorno de chamada (observe algo? Ligar de volta ?). Qualquer declaração que vem depois dessa chamada é executada antes da chamada de retorno.
Solução (s)
Adote a natureza assíncrona do JavaScript! Embora certas operações assíncronas forneçam contrapartes síncronas (o mesmo acontece com "Ajax"), geralmente é desencorajado usá-las, especialmente em um contexto de navegador.
Por que isso é ruim, você pergunta?
O JavaScript é executado no segmento da interface do usuário do navegador e qualquer processo de longa duração bloqueará a interface do usuário, deixando de responder. Além disso, há um limite superior no tempo de execução do JavaScript e o navegador perguntará ao usuário se continua ou não a execução.
Tudo isso é uma péssima experiência do usuário. O usuário não poderá saber se tudo está funcionando bem ou não. Além disso, o efeito será pior para usuários com uma conexão lenta.
A seguir, veremos três soluções diferentes, todas construídas umas sobre as outras:
- Promessas com
async/await
(ES2017 +, disponível em navegadores mais antigos se você usar um transpiler ou regenerador)
- Retornos de chamada (populares no nó)
- Promessas com
then()
(ES2015 +, disponível em navegadores mais antigos se você usar uma das muitas bibliotecas de promessas)
Todos os três estão disponíveis nos navegadores atuais e no nó 7+.
ES2017 +: Promessas com async/await
A versão do ECMAScript lançada em 2017 apresentou suporte no nível de sintaxe para funções assíncronas. Com a ajuda de async
e await
, você pode escrever assíncrono em um "estilo síncrono". O código ainda é assíncrono, mas é mais fácil de ler / entender.
async/await
se baseia em promessas: uma async
função sempre retorna uma promessa. await
"desembrulha" uma promessa e resulta no valor com o qual a promessa foi resolvida ou gera um erro se a promessa foi rejeitada.
Importante: Você só pode usar await
dentro de uma async
função. No momento, o nível superior await
ainda não é suportado; portanto, você pode precisar criar um IIFE assíncrono ( expressão de função chamada imediatamente ) para iniciar um async
contexto.
Você pode ler mais sobre async
e await
no MDN.
Aqui está um exemplo que se baseia no atraso acima:
// Using 'superagent' which will return a promise.
var superagent = require('superagent')
// This is isn't declared as `async` because it already returns a promise
function delay() {
// `delay` returns a promise
return new Promise(function(resolve, reject) {
// Only `delay` is able to resolve or reject the promise
setTimeout(function() {
resolve(42); // After 3 seconds, resolve the promise with value 42
}, 3000);
});
}
async function getAllBooks() {
try {
// GET a list of book IDs of the current user
var bookIDs = await superagent.get('/user/books');
// wait for 3 seconds (just for the sake of this example)
await delay();
// GET information about each book
return await superagent.get('/books/ids='+JSON.stringify(bookIDs));
} catch(error) {
// If any of the awaited promises was rejected, this catch block
// would catch the rejection reason
return null;
}
}
// Start an IIFE to use `await` at the top level
(async function(){
let books = await getAllBooks();
console.log(books);
})();
Suporte para versões atuais do navegador e do nóasync/await
. Você também pode oferecer suporte a ambientes mais antigos, transformando seu código no ES5 com a ajuda do regenerador (ou ferramentas que usam o regenerador, como Babel ).
Permitir que as funções aceitem retornos de chamada
Um retorno de chamada é simplesmente uma função passada para outra função. Essa outra função pode chamar a função passada sempre que estiver pronta. No contexto de um processo assíncrono, o retorno de chamada será chamado sempre que o processo assíncrono for concluído. Normalmente, o resultado é passado para o retorno de chamada.
No exemplo da pergunta, você pode foo
aceitar um retorno de chamada e usá-lo como success
retorno de chamada. Então, é isso
var result = foo();
// Code that depends on 'result'
torna-se
foo(function(result) {
// Code that depends on 'result'
});
Aqui nós definimos a função "inline", mas você pode passar qualquer referência de função:
function myCallback(result) {
// Code that depends on 'result'
}
foo(myCallback);
foo
em si é definido da seguinte forma:
function foo(callback) {
$.ajax({
// ...
success: callback
});
}
callback
irá se referir à função para a qual passamos foo
quando a chamamos e simplesmente a passamos para success
. Ou seja, uma vez que a solicitação do Ajax for bem-sucedida, $.ajax
chamará callback
e passará a resposta para o retorno de chamada (que pode ser referido result
, pois é assim que definimos o retorno de chamada).
Você também pode processar a resposta antes de passá-la para o retorno de chamada:
function foo(callback) {
$.ajax({
// ...
success: function(response) {
// For example, filter the response
callback(filtered_response);
}
});
}
É mais fácil escrever código usando retornos de chamada do que parece. Afinal, o JavaScript no navegador é fortemente orientado a eventos (eventos DOM). Receber a resposta do Ajax nada mais é do que um evento.
Dificuldades podem surgir quando você precisa trabalhar com código de terceiros, mas a maioria dos problemas pode ser resolvida apenas pensando no fluxo do aplicativo.
ES2015 +: Promessas com then ()
A API Promise é um novo recurso do ECMAScript 6 (ES2015), mas já possui um bom suporte ao navegador . Existem também muitas bibliotecas que implementam a API Promises padrão e fornecem métodos adicionais para facilitar o uso e a composição de funções assíncronas (por exemplo, bluebird ).
Promessas são recipientes para valores futuros . Quando a promessa recebe o valor (é resolvido ) ou quando é cancelada ( rejeitada ), notifica todos os seus "ouvintes" que desejam acessar esse valor.
A vantagem sobre os retornos de chamada simples é que eles permitem desacoplar seu código e são mais fáceis de compor.
Aqui está um exemplo simples de usar uma promessa:
function delay() {
// `delay` returns a promise
return new Promise(function(resolve, reject) {
// Only `delay` is able to resolve or reject the promise
setTimeout(function() {
resolve(42); // After 3 seconds, resolve the promise with value 42
}, 3000);
});
}
delay()
.then(function(v) { // `delay` returns a promise
console.log(v); // Log the value once it is resolved
})
.catch(function(v) {
// Or do something else if it is rejected
// (it would not happen in this example, since `reject` is not called).
});
Aplicados à nossa chamada do Ajax, poderíamos usar promessas como esta:
function ajax(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
resolve(this.responseText);
};
xhr.onerror = reject;
xhr.open('GET', url);
xhr.send();
});
}
ajax("/echo/json")
.then(function(result) {
// Code depending on result
})
.catch(function() {
// An error occurred
});
A descrição de todas as vantagens que a promessa oferece está além do escopo desta resposta, mas se você escrever um novo código, considere-o seriamente. Eles fornecem uma ótima abstração e separação do seu código.
Mais informações sobre promessas: rochas HTML5 - Promessas JavaScript
Nota lateral: objetos adiados do jQuery
Objetos adiados são a implementação personalizada de promessas do jQuery (antes da padronização da API da promessa). Eles se comportam quase como promessas, mas expõem uma API ligeiramente diferente.
Todo método Ajax do jQuery já retorna um "objeto adiado" (na verdade, a promessa de um objeto adiado) que você pode retornar da sua função:
function ajax() {
return $.ajax(...);
}
ajax().done(function(result) {
// Code depending on result
}).fail(function() {
// An error occurred
});
Nota lateral: dicas da promessa
Lembre-se de que promessas e objetos adiados são apenas contêineres para um valor futuro, eles não são o valor em si. Por exemplo, suponha que você tenha o seguinte:
function checkPassword() {
return $.ajax({
url: '/password',
data: {
username: $('#username').val(),
password: $('#password').val()
},
type: 'POST',
dataType: 'json'
});
}
if (checkPassword()) {
// Tell the user they're logged in
}
Este código entende mal os problemas de assincronia acima. Especificamente, $.ajax()
não congela o código enquanto verifica a página '/ senha' no servidor - envia uma solicitação ao servidor e, enquanto espera, retorna imediatamente um objeto adiado jQuery Ajax Deferred, não a resposta do servidor. Isso significa que a if
instrução sempre obterá esse objeto adiado, trate-o como true
e continue como se o usuário estivesse logado. Nada bom.
Mas a correção é fácil:
checkPassword()
.done(function(r) {
if (r) {
// Tell the user they're logged in
} else {
// Tell the user their password was bad
}
})
.fail(function(x) {
// Tell the user something bad happened
});
Não recomendado: chamadas síncronas "Ajax"
Como mencionei, algumas operações assíncronas (!) Possuem contrapartes síncronas. Eu não defendo o uso deles, mas, por uma questão de integridade, eis como você faria uma chamada síncrona:
Sem jQuery
Se você usar um XMLHTTPRequest
objeto diretamente , passe false
como terceiro argumento para .open
.
jQuery
Se você usa o jQuery , pode definir a async
opção para false
. Observe que esta opção está obsoleta desde o jQuery 1.8. Você ainda pode usar um success
retorno de chamada ou acessar a responseText
propriedade do objeto jqXHR :
function foo() {
var jqXHR = $.ajax({
//...
async: false
});
return jqXHR.responseText;
}
Se você usar qualquer outro método jQuery Ajax, como $.get
, $.getJSON
etc., precisará alterá-lo para $.ajax
(já que você só pode passar parâmetros de configuração para $.ajax
).
Atenção! Não é possível fazer uma solicitação JSONP síncrona . O JSONP por sua própria natureza é sempre assíncrono (mais um motivo para nem considerar essa opção).
If you use any other jQuery AJAX method, such as $.get, $.getJSON, etc., you have them to $.ajax.
(Sim, eu percebo que meu nick é um pouco irônico, neste caso)foo
é chamado e uma função é passada para ele (foo(function(result) {....});
)?result
é usado dentro desta função e é a resposta da solicitação do Ajax. Para se referir a essa função, o primeiro parâmetro de foo é chamadocallback
e atribuído emsuccess
vez de uma função anônima. Então,$.ajax
ligarácallback
quando a solicitação for bem-sucedida. Eu tentei explicar um pouco mais.$.getJSON
se quiser que a solicitação do Ajax seja síncrona. No entanto, você não deve querer que a solicitação seja síncrona, para que isso não se aplique. Você deve usar retornos de chamada ou promessas para lidar com a resposta, conforme explicado anteriormente na resposta.Se você não estiver usando jQuery no seu código, esta resposta é para você
Seu código deve ser algo parecido com isto:
Felix Kling fez um bom trabalho ao escrever uma resposta para as pessoas que usam o jQuery para AJAX. Decidi fornecer uma alternativa para as pessoas que não o são.
( Observe que, para aqueles que usam a nova
fetch
API, Angular ou promessas, adicionei outra resposta abaixo )O que você está enfrentando
Este é um breve resumo de "Explicação do problema" da outra resposta, se você não tiver certeza depois de ler isso, leia isso.
O Um em AJAX significa assíncrona . Isso significa que o envio da solicitação (ou melhor, o recebimento da resposta) é retirado do fluxo de execução normal. No seu exemplo,
.send
retorna imediatamente e a próxima instruçãoreturn result;
,, é executada antes da função que você passou comosuccess
retorno de chamada ser chamada.Isso significa que, quando você está retornando, o ouvinte que você definiu ainda não foi executado, o que significa que o valor que você está retornando não foi definido.
Aqui está uma analogia simples
(Violino)
O valor
a
retornado éundefined
porque aa=5
peça ainda não foi executada. O AJAX age assim: você retorna o valor antes que o servidor tenha a chance de informar ao seu navegador qual é esse valor.Uma solução possível para esse problema é codificar de forma reativa , informando ao seu programa o que fazer quando o cálculo for concluído.
Isso é chamado de CPS . Basicamente, estamos passando
getFive
uma ação para executar quando ela é concluída, informando ao nosso código como reagir quando um evento é concluído (como nossa chamada AJAX ou, neste caso, o tempo limite).O uso seria:
O que deve alertar "5" para a tela. (Violino) .
Soluções possíveis
Existem basicamente duas maneiras de resolver isso:
1. AJAX síncrono - não faça isso !!
Quanto ao AJAX síncrono, não faça isso! A resposta de Felix levanta alguns argumentos convincentes sobre por que é uma má ideia. Para resumir, congelará o navegador do usuário até que o servidor retorne a resposta e crie uma experiência muito ruim para o usuário. Aqui está outro pequeno resumo do MDN sobre o porquê:
Se você precisar fazer isso, pode passar uma bandeira: Aqui está como:
2. Reestruturar o código
Deixe sua função aceitar um retorno de chamada. No exemplo de código, você
foo
pode aceitar um retorno de chamada. Nós estaremos dizendo ao nosso código como reagir quandofoo
concluir.Assim:
Torna-se:
Aqui passamos uma função anônima, mas podemos facilmente passar uma referência a uma função existente, fazendo com que pareça:
Para mais detalhes sobre como esse tipo de design de retorno de chamada é feito, consulte a resposta de Felix.
Agora, vamos definir o próprio foo para agir de acordo
(violino)
Agora fizemos nossa função foo aceitar uma ação a ser executada quando o AJAX for concluído com êxito. Podemos estender isso ainda mais, verificando se o status da resposta não é 200 e agindo de acordo (crie um manipulador de falhas e outros). Resolvendo efetivamente nosso problema.
Se você ainda está com dificuldades para entender isso, leia o guia de introdução do AJAX na MDN.
fonte
onload
manipulador, que só dispara quandoreadyState
é4
. Obviamente, não é suportado no IE8. (iirc, pode precisar de confirmação.) #XMLHttpRequest 2 (leia primeiro as respostas de Benjamin Gruenbaum e Felix Kling )
Se você não usa o jQuery e deseja um XMLHttpRequest 2 curto e agradável que funcione nos navegadores modernos e também nos navegadores móveis, sugiro usá-lo desta maneira:
Como você pode ver:
Há duas maneiras de obter a resposta dessa chamada do Ajax (três usando o nome de var XMLHttpRequest):
O mais simples:
Ou se, por algum motivo, você
bind()
retornar a chamada para uma classe:Exemplo:
Ou (acima, as funções anônimas são melhores são sempre um problema):
Nada mais fácil.
Agora, algumas pessoas provavelmente dirão que é melhor usar onreadystatechange ou até o nome da variável XMLHttpRequest. Isto é errado.
Confira os recursos avançados do XMLHttpRequest
Ele suporta todos os * navegadores modernos. E posso confirmar que estou usando essa abordagem, já que o XMLHttpRequest 2 existe. Nunca tive nenhum tipo de problema em todos os navegadores que uso.
onreadystatechange só é útil se você deseja obter os cabeçalhos no estado 2.
Usar o
XMLHttpRequest
nome da variável é outro grande erro, pois você precisa executar o retorno de chamada dentro dos fechamentos onload / oreadystatechange, caso contrário você o perdeu.Agora, se você quiser algo mais complexo usando post e FormData, poderá estender facilmente esta função:
Mais uma vez ... é uma função muito curta, mas recebe e publica.
Exemplos de uso:
Ou passe um elemento de formulário completo (
document.getElementsByTagName('form')[0]
):Ou defina alguns valores personalizados:
Como você pode ver, eu não implementei a sincronização ... é uma coisa ruim.
Dito isto ... por que não fazer isso da maneira mais fácil?
Como mencionado no comentário, o uso do erro && synchronous quebra completamente o ponto da resposta. Qual é uma maneira curta e agradável de usar o Ajax da maneira correta?
Manipulador de erro
No script acima, você possui um manipulador de erros definido estaticamente para que não comprometa a função. O manipulador de erros também pode ser usado para outras funções.
Mas realmente obter um erro, a única maneira é escrever um URL errado; nesse caso, todo navegador gera um erro.
Os manipuladores de erro talvez sejam úteis se você definir cabeçalhos personalizados, definir o responseType como buffer da matriz de blob ou qualquer outra coisa ...
Mesmo se você passar 'POSTAPAPAP' como método, isso não causará erro.
Mesmo se você passar 'fdggdgilfdghfldj' como formdata, isso não causará um erro.
No primeiro caso, o erro está dentro do
displayAjax()
underthis.statusText
asMethod not Allowed
.No segundo caso, simplesmente funciona. Você deve verificar no lado do servidor se passou os dados corretos da postagem.
o domínio cruzado não permitido gera erro automaticamente.
Na resposta a erro, não há códigos de erro.
Existe apenas o
this.type
que está definido como erro.Por que adicionar um manipulador de erros se você não tem controle total sobre erros? A maioria dos erros é retornada dentro disso na função de retorno de chamada
displayAjax()
.Portanto: não há necessidade de verificação de erros se você conseguir copiar e colar o URL corretamente. ;)
PS: Como o primeiro teste, eu escrevi x ('x', displayAjax) ... e ele obteve uma resposta total ... ??? Então, verifiquei a pasta em que o HTML está localizado e havia um arquivo chamado 'x.xml'. Portanto, mesmo se você esquecer a extensão do seu arquivo, XMLHttpRequest 2 ENCONTRA-O . EU LOL
Ler um arquivo síncrono
Não faça isso.
Se você deseja bloquear o navegador por um tempo, carregue um bom
.txt
arquivo grande e síncrono.Agora você pode fazer
Não há outra maneira de fazer isso de maneira não assíncrona. (Sim, com loop setTimeout ... mas sério?)
Outro ponto é ... se você trabalha com APIs ou apenas os arquivos da sua própria lista ou o que quer que use sempre funções diferentes para cada solicitação ...
Somente se você tiver uma página na qual carregue sempre o mesmo XML / JSON ou o que precisar, precisará de apenas uma função. Nesse caso, modifique um pouco a função Ajax e substitua b por sua função especial.
As funções acima são para uso básico.
Se você deseja estender a função ...
Sim você pode.
Estou usando muitas APIs e uma das primeiras funções que integro a todas as páginas HTML é a primeira função Ajax nesta resposta, apenas com GET ...
Mas você pode fazer muitas coisas com o XMLHttpRequest 2:
Criei um gerenciador de downloads (usando intervalos de ambos os lados com currículo, leitor de arquivos, sistema de arquivos), vários conversores de redimensionadores de imagens usando canvas, preenchendo bancos de dados SQL da web com base64images e muito mais ... Mas nesses casos, você deve criar uma função apenas para isso finalidade ... às vezes você precisa de um blob, buffers de matriz, pode definir cabeçalhos, substituir o tipo de mim e há muito mais ...
Mas a questão aqui é como retornar uma resposta do Ajax ... (adicionei uma maneira fácil.)
fonte
x
,ajax
ouxhr
pode ser mais agradável :)). Não vejo como ele trata o retorno da resposta de uma chamada AJAX. (alguém ainda pode fazervar res = x("url")
e não entender por que não funciona;)). Em uma nota lateral - seria legal se você retornassec
do método para que os usuários possam se conectarerror
etc.2.ajax is meant to be async.. so NO var res=x('url')..
Esse é o ponto inteiro desta questão e respostas :)Se você estiver usando promessas, esta resposta é para você.
Isso significa AngularJS, jQuery (com adiado), substituição nativa do XHR (busca), EmberJS, salvamento do BackboneJS ou qualquer biblioteca de nós que retorne promessas.
Seu código deve ser algo parecido com isto:
Felix Kling fez um bom trabalho ao escrever uma resposta para as pessoas que usam jQuery com retornos de chamada para AJAX. Eu tenho uma resposta para XHR nativo. Esta resposta é para uso genérico de promessas no front-end ou no back-end.
A questão central
O modelo de simultaneidade JavaScript no navegador e no servidor com NodeJS / io.js é assíncrono e reativo .
Sempre que você chama um método que retorna uma promessa, os
then
manipuladores são sempre executados de forma assíncrona - ou seja, após o código abaixo deles que não está em um.then
manipulador.Isso significa que, quando você está retornando,
data
othen
manipulador que você definiu ainda não foi executado. Por sua vez, isso significa que o valor que você está retornando não foi definido com o valor correto no tempo.Aqui está uma analogia simples para o problema:
O valor de
data
éundefined
porque adata = 5
peça ainda não foi executada. Provavelmente será executado em um segundo, mas a essa altura é irrelevante para o valor retornado.Como a operação ainda não aconteceu (AJAX, chamada do servidor, IO, timer), você está retornando o valor antes que a solicitação tenha a chance de informar ao seu código qual é esse valor.
Uma solução possível para esse problema é codificar de forma reativa , informando ao seu programa o que fazer quando o cálculo for concluído. As promessas ativam isso ativamente por serem temporais (sensíveis ao tempo) por natureza.
Resumo rápido das promessas
Uma promessa é um valor ao longo do tempo . As promessas têm estado, elas começam como pendentes sem valor e podem se estabelecer em:
Uma promessa só pode mudar de estado uma vez, após o que sempre permanecerá no mesmo estado para sempre. Você pode anexar
then
manipuladores a promessas para extrair seu valor e manipular erros.then
manipuladores permitem encadear chamadas. As promessas são criadas usando APIs que as retornam . Por exemplo, a substituição AJAX mais modernafetch
ou o jQuery$.get
retorno prometem.Quando exigimos
.then
uma promessa e devolvemos algo dela - obtemos uma promessa para o valor processado . Se retornarmos outra promessa, teremos coisas incríveis, mas vamos segurar nossos cavalos.Com promessas
Vamos ver como podemos resolver o problema acima com promessas. Primeiro, vamos demonstrar nossa compreensão dos estados de promessa acima, usando o construtor Promise para criar uma função de atraso:
Agora, depois que convertemos setTimeout para usar promessas, podemos usar
then
para fazer valer:Basicamente, em vez de retornar um valor que não podemos fazer por causa do modelo de concorrência - estamos retornando um invólucro para um valor que podemos desembrulhar com
then
. É como uma caixa com a qual você pode abrirthen
.Aplicando isso
Isso significa o mesmo para sua chamada de API original, você pode:
Então, isso funciona tão bem. Aprendemos que não podemos retornar valores de chamadas já assíncronas, mas podemos usar promessas e encadeá-las para executar o processamento. Agora sabemos como retornar a resposta de uma chamada assíncrona.
ES2015 (ES6)
O ES6 apresenta geradores que são funções que podem retornar no meio e retomar o ponto em que estavam. Isso geralmente é útil para sequências, por exemplo:
É uma função que retorna um iterador sobre a sequência
1,2,3,3,3,3,....
que pode ser iterada. Embora isso seja interessante por si só e abra espaço para muitas possibilidades, há um caso interessante em particular.Se a sequência que estamos produzindo é uma sequência de ações, e não números - podemos pausar a função sempre que uma ação é produzida e aguardá-la antes de retomar a função. Então, em vez de uma sequência de números, precisamos de uma sequência de futuros valores - ou seja: promessas.
Esse truque um tanto complicado, mas muito poderoso, permite escrever código assíncrono de maneira síncrona. Existem vários "corredores" que fazem isso por você, escrevendo um com poucas linhas de código, mas está além do escopo desta resposta. Vou usar o Bluebird's
Promise.coroutine
aqui, mas existem outros wrappers comoco
orQ.async
.Esse método retorna uma promessa em si, que podemos consumir de outras corotinas. Por exemplo:
ES2016 (ES7)
No ES7, isso é padronizado ainda mais, existem várias propostas no momento, mas em todas elas você pode
await
prometer. Isso é apenas "açúcar" (melhor sintaxe) para a proposta ES6 acima, adicionando as palavrasasync
-await
chave e . Fazendo o exemplo acima:Ele ainda retorna uma promessa da mesma forma :)
fonte
return await data.json();
?)Você está usando o Ajax incorretamente. A idéia é não fazer com que ele retorne nada, mas entregue os dados a algo chamado função de retorno de chamada, que lida com os dados.
Isso é:
Retornar qualquer coisa no manipulador de envio não fará nada. Em vez disso, você deve entregar os dados ou fazer o que quiser diretamente dentro da função de sucesso.
fonte
success: handleData
e funcionaria.success
método, é o escopo circundante de$.ajax
.A solução mais simples é criar uma função JavaScript e chamá-la para o
success
retorno de chamada do Ajax .fonte
Vou responder com uma história em quadrinhos horrível, desenhada à mão. A segunda imagem é a razão pela qual
result
estáundefined
no seu exemplo de código.fonte
Angular1
Para pessoas que estão usando o AngularJS , podem lidar com essa situação usando
Promises
.Aqui diz:
Você pode encontrar uma boa explicação aqui também.
Exemplo encontrado nos documentos mencionados abaixo.
Angular2 e mais tarde
Veja
Angular2
o exemplo a seguir, mas é recomendável usarObservables
comAngular2
.}
Você pode consumir dessa maneira,
Veja o post original aqui. Porém, o Typescript não suporta o es6 Promises nativo ; se você quiser usá-lo, pode ser necessário um plugin para isso.
Além disso, aqui estão as especificações de promessas definidas aqui.
fonte
A maioria das respostas aqui fornece sugestões úteis para quando você tem uma única operação assíncrona, mas às vezes isso ocorre quando você precisa executar uma operação assíncrona para cada entrada em uma matriz ou outra estrutura semelhante a uma lista. A tentação é fazer isso:
Exemplo:
Mostrar snippet de código
O motivo para isso não funcionar é que os retornos de chamada
doSomethingAsync
ainda não foram executados no momento em que você está tentando usar os resultados.Portanto, se você possui uma matriz (ou algum tipo de lista) e deseja executar operações assíncronas para cada entrada, você tem duas opções: Execute as operações em paralelo (sobreposição) ou em série (uma após a outra em sequência).
Paralelo
Você pode iniciar todos eles e acompanhar quantas chamadas de retorno espera e, em seguida, usar os resultados quando receber tantas chamadas de retorno:
Exemplo:
Mostrar snippet de código
(Nós poderíamos acabar com
expecting
e apenas usarresults.length === theArray.length
, mas isso nos deixa abertos à possibilidade detheArray
mudar enquanto as chamadas são excelentes ...)Observe como usamos a
index
partir deforEach
para salvar o resultado naresults
mesma posição da entrada a que se refere, mesmo que os resultados cheguem fora de ordem (já que as chamadas assíncronas não são necessariamente concluídas na ordem em que foram iniciadas).Mas e se você precisar retornar esses resultados de uma função? Como as outras respostas apontaram, você não pode; você precisa que sua função aceite e chame um retorno de chamada (ou retorne uma promessa ). Aqui está uma versão de retorno de chamada:
Exemplo:
Mostrar snippet de código
Ou aqui está uma versão retornando um
Promise
:Claro se
doSomethingAsync
nos passassem erros, usaríamosreject
para rejeitar a promessa quando recebíamos um erro.)Exemplo:
Mostrar snippet de código
(Ou, alternativamente, você pode fazer um invólucro para
doSomethingAsync
que retorne uma promessa e fazer o seguinte ...)Se
doSomethingAsync
lhe der uma promessa , você pode usarPromise.all
:Se você sabe que
doSomethingAsync
isso ignorará um segundo e um terceiro argumento, você pode apenas passá-lo diretamente paramap
(map
chama seu retorno de chamada com três argumentos, mas a maioria das pessoas usa apenas o primeiro na maior parte do tempo):Exemplo:
Mostrar snippet de código
Observe que
Promise.all
resolve sua promessa com uma variedade de resultados de todas as promessas que você faz quando todas são resolvidas ou rejeita sua promessa quando a primeira das promessas que você rejeita.Series
Suponha que você não queira que as operações sejam paralelas? Se você deseja executá-los um após o outro, precisará aguardar a conclusão de cada operação antes de iniciar a próxima. Aqui está um exemplo de uma função que faz isso e chama um retorno de chamada com o resultado:
(Como estamos fazendo o trabalho em série, podemos apenas usá-lo,
results.push(result)
pois sabemos que não obteremos resultados fora de ordem. No exemplo acima, poderíamos ter usadoresults[index] = result;
, mas em alguns dos exemplos a seguir não temos um índice usar.)Exemplo:
Mostrar snippet de código
(Ou, novamente, crie um invólucro para
doSomethingAsync
que você prometa e faça o abaixo ...)Se
doSomethingAsync
lhe der uma promessa, se você puder usar a sintaxe do ES2017 + (talvez com um transpilador como o Babel ), poderá usar umaasync
função comfor-of
eawait
:Exemplo:
Mostrar snippet de código
Se você ainda não pode usar a sintaxe do ES2017 +, pode usar uma variação no padrão "Redução de promessas" (isso é mais complexo que a redução de promessas usual porque não estamos passando o resultado de um para o outro, mas sim reunindo seus resultados em uma matriz):
Exemplo:
Mostrar snippet de código
... o que é menos complicado com as funções de seta do ES2015 + :
Exemplo:
Mostrar snippet de código
fonte
if (--expecting === 0)
parte do código funciona, por favor? A versão de retorno da sua solução está funcionando muito bem para mim, mas não entendo como, com essa declaração, você está verificando o número de respostas concluídas. Aprecio que é apenas falta de conhecimento da minha parte. Existe uma maneira alternativa de verificar esse cheque?expecting
começa com o valor dearray.length
, que é quantas solicitações vamos fazer. Sabemos que o retorno de chamada não será chamado até que todas essas solicitações sejam iniciadas. No retorno de chamada,if (--expecting === 0)
faz o seguinte: 1. Decrementosexpecting
(recebemos uma resposta, portanto esperamos uma resposta a menos) e se o valor após o decréscimo for 0 (não esperamos mais respostas), estamos feito!results
não existia). :-) Corrigido.Veja este exemplo:
Como você pode ver,
getJoke
está retornando uma promessa resolvida (é resolvida ao retornarres.data.value
). Portanto, você espera até que a solicitação $ http.get seja concluída e o console.log (res.joke) seja executado (como um fluxo assíncrono normal).Este é o plnkr:
http://embed.plnkr.co/XlNR7HpCaIhJxskMJfSg/
Caminho ES6 (assíncrono - aguardar)
fonte
Este é um dos lugares em que o conceito de vinculação ou armazenamento de dados usado em muitas novas estruturas JavaScript funcionará muito bem para você ...
Portanto, se você estiver usando Angular, React ou qualquer outra estrutura que execute duas formas de vinculação de dados ou conceito de armazenamento, esse problema será simplesmente corrigido para você. Assim, em palavras simples, seu resultado será
undefined
o primeiro estágio, portanto, você deve obterresult = undefined
antes de receber o dados, assim que você obtiver o resultado, ele será atualizado e atribuído ao novo valor que resposta da sua chamada Ajax ...Mas como você pode fazer isso em javascript puro ou jQuery, por exemplo, como você fez nesta pergunta?
Você pode usar um retorno de chamada , promessa e observável recentemente para lidar com isso, por exemplo, em promessas que temos algumas funções como
success()
outhen()
que serão executadas quando seus dados estiverem prontos para você, o mesmo que com a função de retorno de chamada ou assinatura observável .Por exemplo, no seu caso em que você está usando jQuery , você pode fazer algo assim:
Para obter mais informações, estude sobre promessas e observáveis, que são maneiras mais recentes de fazer isso de forma assíncrona.
fonte
$.ajax({url: "api/data", success: fooDone.bind(this)});
É um problema muito comum que enfrentamos enquanto lutamos com os 'mistérios' do JavaScript. Deixe-me tentar desmistificar esse mistério hoje.
Vamos começar com uma simples função JavaScript:
É uma simples chamada de função síncrona (onde cada linha de código é 'finalizada com seu trabalho' antes da próxima em sequência), e o resultado é o mesmo que o esperado.
Agora, vamos adicionar um pouco de distorção, introduzindo pouco atraso em nossa função, para que todas as linhas de código não sejam 'finalizadas' em sequência. Assim, ele emulará o comportamento assíncrono da função:
Então lá está, esse atraso acabou com a funcionalidade que esperávamos! Mas o que exatamente aconteceu? Bem, é realmente muito lógico se você olhar para o código. a função
foo()
, na execução, não retorna nada (o valor retornado éundefined
), mas inicia um timer, que executa uma função após 1s para retornar 'wohoo'. Mas como você pode ver, o valor atribuído à barra é o material retornado imediatamente de foo (), que não é nada, é apenas justoundefined
.Então, como lidamos com esse problema?
Vamos pedir à nossa função uma PROMESSA . Promessa é realmente sobre o que isso significa: significa que a função garante que você forneça qualquer saída que obtiver no futuro. então vamos vê-lo em ação para o nosso pequeno problema acima:
Assim, o resumo é - para lidar com funções assíncronas, como chamadas baseadas em ajax, etc., você pode usar uma promessa ao
resolve
valor (que pretende retornar). Assim, em resumo, você resolve o valor em vez de retornar , em funções assíncronas.UPDATE (Promessas com assíncrono / espera)
Além de
then/catch
trabalhar com promessas, existe mais uma abordagem. A idéia é reconhecer uma função assíncrona e esperar as promessas serem resolvidas antes de passar para a próxima linha de código. Ainda é apenas umpromises
segredo, mas com uma abordagem sintática diferente. Para tornar as coisas mais claras, você pode encontrar uma comparação abaixo:então / catch versão:
versão assíncrona / aguardada:
fonte
Outra abordagem para retornar um valor de uma função assíncrona é passar um objeto que armazenará o resultado da função assíncrona.
Aqui está um exemplo do mesmo:
Estou usando o
result
objeto para armazenar o valor durante a operação assíncrona. Isso permite que o resultado esteja disponível mesmo após o trabalho assíncrono.Eu uso muito essa abordagem. Eu estaria interessado em saber como essa abordagem funciona quando está envolvido o retorno do resultado através de módulos consecutivos.
fonte
result
. Funciona porque você está lendo a variável após a conclusão da função assíncrona.Embora promessas e retornos de chamada funcionem bem em muitas situações, é difícil expressar algo como:
Você acabaria passando
async1
; verifique sename
está indefinido ou não e chame o retorno de chamada adequadamente.Embora seja bom em pequenos exemplos, fica irritante quando você tem muitos casos semelhantes e tratamento de erros envolvidos.
Fibers
ajuda a resolver o problema.Você pode conferir o projeto aqui .
fonte
async-await
se estiver usando algumas das versões mais recentes do nó. Se alguém está preso com versões mais antigas, ele pode usar esse método.O exemplo a seguir que escrevi mostra como
Este exemplo de trabalho é independente. Ele definirá um objeto de solicitação simples que usa o
XMLHttpRequest
objeto de janela para fazer chamadas. Ele definirá uma função simples para aguardar a conclusão de várias promessas.Contexto. O exemplo é consultar o ponto de extremidade da API da Web do Spotify para procurar
playlist
objetos para um determinado conjunto de cadeias de consulta:Para cada item, uma nova promessa acionará um bloco -
ExecutionBlock
, analise o resultado, programe um novo conjunto de promessas com base na matriz de resultados, que é uma lista deuser
objetos do Spotify e execute a nova chamada HTTP deExecutionProfileBlock
forma assíncrona.Você pode ver uma estrutura Promise aninhada, que permite gerar várias chamadas HTTP aninhadas completamente assíncronas e juntar os resultados de cada subconjunto de chamadas
Promise.all
.NOTA As
search
APIs recentes do Spotify exigirão que um token de acesso seja especificado nos cabeçalhos da solicitação:Portanto, para executar o exemplo a seguir, você precisa colocar seu token de acesso nos cabeçalhos da solicitação:
Eu discuti extensivamente esta solução aqui .
fonte
Resposta curta: você precisa implementar um retorno de chamada como este:
fonte
Resposta de 2017: agora você pode fazer exatamente o que deseja em todos os navegadores e nós atuais
Isso é bem simples:
Aqui está uma versão funcional do seu código:
aguardar é suportado em todos os navegadores atuais e no nó 8
fonte
await/async
O navegador pode ser dividido em três partes:
1) Loop de Eventos
2) API da Web
3) Fila de Eventos
O loop de eventos é executado para sempre, ou seja, é um tipo de loop infinito. A fila de eventos é onde todas as suas funções são pressionadas em algum evento (exemplo: clique); este é um por um realizado na fila e colocado no loop de eventos que executa essa função e se prepara automaticamente para o próximo após o primeiro ser executado. Isso significa que a execução de uma função não inicia até que a função antes da fila seja executada no loop de eventos.
Agora, vamos pensar que pressionamos duas funções em uma fila, uma para obter dados do servidor e outra utiliza esses dados. A função serverRequest entra no loop de eventos e faz uma chamada para o servidor, pois nunca sabemos quanto tempo levará para obter dados do servidor, portanto, espera-se que esse processo leve tempo e ocupamos nosso loop de eventos, pendurando nossa página, é aí que a Web A API entra em função, assume essa função do loop de eventos e lida com o servidor, liberando o loop de eventos, para que possamos executar a próxima função da fila. A próxima função na fila é utiliseData () que entra em loop, mas por causa de nenhum dado disponível, ele vai o desperdício e a execução da próxima função continuam até o final da fila (isso é chamado de chamada assíncrona, ou seja, podemos fazer outra coisa até obtermos dados)
Vamos supor que nossa função serverRequest () tenha uma declaração de retorno em um código, quando recuperarmos os dados da API da Web do servidor, eles serão colocados na fila no final da fila. Como é empurrado no final da fila, não podemos utilizar seus dados, pois não há nenhuma função em nossa fila para utilizá-los. Portanto, não é possível retornar algo do Async Call.
Portanto, a solução para isso é retorno ou promessa .
Uma imagem de uma das respostas aqui, explica corretamente o uso de retorno de chamada ... Damos nossa função (função que utiliza dados retornados do servidor) para funcionar como servidor de chamada.
No meu código é chamado como
Retorno de chamada Javscript.info
fonte
Você pode usar esta biblioteca personalizada (gravada usando o Promise) para fazer uma chamada remota.
Exemplo de uso simples:
fonte
Outra solução é executar o código via executor seqüencial nsynjs .
Se a função subjacente for prometida
O nsynjs avaliará todas as promessas sequencialmente e colocará o resultado da promessa na
data
propriedade:Se a função subjacente não for prometida
Etapa 1. Função Wrap com retorno de chamada no wrapper compatível com nsynjs (se houver uma versão promissificada, você pode pular esta etapa):
Etapa 2. Coloque a lógica síncrona em função:
Etapa 3. Execute a função de maneira síncrona via nsynjs:
O Nsynjs avaliará todos os operadores e expressões passo a passo, interrompendo a execução, caso o resultado de alguma função lenta não esteja pronto.
Mais exemplos aqui: https://github.com/amaksr/nsynjs/tree/master/examples
fonte
O ECMAScript 6 possui 'geradores' que permitem programar facilmente em um estilo assíncrono.
Para executar o código acima, faça o seguinte:
Se você precisar direcionar navegadores que não suportam o ES6, execute o código por meio do Babel ou do compilador de fechamento para gerar o ECMAScript 5.
O retorno de chamada
...args
é agrupado em uma matriz e destruído quando você os lê, para que o padrão possa lidar com retornos de chamada que possuem vários argumentos. Por exemplo, com o nó fs :fonte
Aqui estão algumas abordagens para trabalhar com solicitações assíncronas:
Exemplo: Implementação adiada do jQuery para trabalhar com várias solicitações
fonte
Nós nos encontramos em um universo que parece progredir ao longo de uma dimensão que chamamos de "tempo". Nós realmente não entendemos o que é o tempo, mas desenvolvemos abstrações e vocabulários que nos permitem raciocinar e falar sobre isso: "passado", "presente", "futuro", "antes", "depois".
Os sistemas de computador que construímos - cada vez mais - têm o tempo como uma dimensão importante. Certas coisas estão configuradas para acontecer no futuro. Então outras coisas precisam acontecer depois que essas primeiras coisas acabarem. Essa é a noção básica chamada "assincronicidade". Em nosso mundo cada vez mais em rede, o caso mais comum de assincronicidade está aguardando que algum sistema remoto responda a alguma solicitação.
Considere um exemplo. Você chama o leiteiro e pede um pouco de leite. Quando chegar, você quer colocá-lo no seu café. Você não pode colocar o leite no café agora, porque ainda não está aqui. Você precisa esperar que chegue antes de colocá-lo no café. Em outras palavras, o seguinte não funcionará:
Como o JS não tem como saber que ele precisa esperar para
order_milk
concluir antes de executarput_in_coffee
. Em outras palavras, ele não sabe queorder_milk
é assíncrono - é algo que não resultará em leite até algum tempo futuro. JS e outras linguagens declarativas executam uma instrução após a outra sem esperar.A abordagem clássica da JS para esse problema, aproveitando o fato de que a JS suporta funções como objetos de primeira classe que podem ser passados, é passar uma função como parâmetro para a solicitação assíncrona, que será chamada depois que for concluída sua tarefa em algum momento no futuro. Essa é a abordagem de "retorno de chamada". Se parece com isso:
order_milk
começa, pede o leite e, quando e somente quando chega, invocaput_in_coffee
.O problema com essa abordagem de retorno de chamada é que polui a semântica normal de uma função que informa seu resultado
return
; em vez disso, as funções não devem relatar seus resultados chamando um retorno de chamada fornecido como parâmetro. Além disso, essa abordagem pode rapidamente tornar-se difícil de lidar quando se lida com sequências mais longas de eventos. Por exemplo, digamos que quero esperar que o leite seja colocado no café e só então execute uma terceira etapa, ou seja, beber o café. Acabo precisando escrever algo como isto:onde estou passando
put_in_coffee
o leite para colocá-lo e também a ação (drink_coffee
) a ser executada depois que o leite for colocado. Esse código fica difícil de escrever, ler e depurar.Nesse caso, poderíamos reescrever o código na pergunta como:
Digite promessas
Essa foi a motivação para a noção de "promessa", que é um tipo particular de valor que representa um resultado futuro ou assíncrono de algum tipo. Pode representar algo que já aconteceu, ou que acontecerá no futuro, ou que talvez nunca aconteça. As promessas têm um único método, nomeado
then
, ao qual você passa uma ação a ser executada quando o resultado que a promessa representa tiver sido realizado.No caso de nosso leite e café, planejamos
order_milk
retornar uma promessa para o leite que chega e, em seguida, especificarput_in_coffee
como umathen
ação, da seguinte maneira:Uma vantagem disso é que podemos agrupá-las para criar sequências de ocorrências futuras ("encadeamento"):
Vamos aplicar promessas ao seu problema específico. Vamos envolver nossa lógica de solicitação dentro de uma função, que retorna uma promessa:
Na verdade, tudo o que fizemos foi adicionado
return
a à chamada de$.ajax
. Isso funciona porque o jQuery$.ajax
já retorna um tipo de promessa. (Na prática, sem entrar em detalhes, preferimos encerrar esta chamada para retornar uma promessa real ou usar alguma alternativa a$.ajax
isso.) Agora, se quisermos carregar o arquivo e esperar que ele termine e então faça alguma coisa, podemos simplesmente dizerpor exemplo,
Ao usar promessas, acabamos transferindo muitas funções para
then
, portanto, geralmente é útil usar as funções de seta mais compactas no estilo ES6:A
async
palavra-chaveMas ainda há algo vagamente insatisfatório em ter que escrever código de uma maneira, se síncrona, e de uma maneira bem diferente, se for assíncrona. Para síncrona, escrevemos
mas se
a
for assíncrono, com promessas temos que escreverAcima, dissemos: "O JS não tem como saber que precisa aguardar a conclusão da primeira chamada antes de executar a segunda". Não seria bom se foi alguma maneira de dizer JS isso? Acontece que existe - a
await
palavra - chave, usada dentro de um tipo especial de função chamada função "assíncrona". Esse recurso faz parte da próxima versão do ES, mas já está disponível em transpilers como Babel, com as predefinições corretas. Isso nos permite simplesmente escreverNo seu caso, você seria capaz de escrever algo como
fonte
Resposta curta : Seu
foo()
método retorna imediatamente, enquanto a$ajax()
chamada é executada de forma assíncrona após o retorno da função . O problema é como ou onde armazenar os resultados recuperados pela chamada assíncrona quando ela retornar.Várias soluções foram fornecidas neste segmento. Talvez a maneira mais fácil seja passar um objeto para o
foo()
método e armazenar os resultados em um membro desse objeto após a conclusão da chamada assíncrona.Observe que a chamada para
foo()
ainda não retornará nada útil. No entanto, o resultado da chamada assíncrona agora será armazenadoresult.response
.fonte
Use uma
callback()
função dentro dofoo()
sucesso. Tente desta maneira. É simples e fácil de entender.fonte
A questão era:
que PODE ser interpretado como:
A solução será evitar retornos de chamada e usar uma combinação de promessas e assíncrono / espera .
Eu gostaria de dar um exemplo para uma solicitação do Ajax.
(Embora possa ser escrito em Javascript, prefiro escrevê-lo em Python e compilá-lo em Javascript usando Transcrypt . Será bastante claro.)
Permite primeiro ativar o uso de JQuery, para ter
$
disponível comoS
:Defina uma função que retorne uma promessa , neste caso, uma chamada Ajax:
Use o código assíncrono como se fosse síncrono :
fonte
Usando Promessa
A resposta mais perfeita para esta pergunta está usando
Promise
.Uso
Mas espere...!
Há um problema com o uso de promessas!
Por que devemos usar nossa própria promessa personalizada?
Eu estava usando esta solução por um tempo até descobrir que havia um erro nos navegadores antigos:
Então, decidi implementar minha própria classe Promise para o ES3 abaixo dos compiladores js, se não estiver definido. Basta adicionar esse código antes do código principal e usar o Promise com segurança!
fonte
É claro que existem muitas abordagens, como solicitação síncrona, promessa, mas, pela minha experiência, acho que você deve usar a abordagem de retorno de chamada. É natural o comportamento assíncrono do Javascript. Portanto, seu snippet de código pode ser reescrito um pouco diferente:
fonte
Em vez de lançar código para você, existem 2 conceitos que são essenciais para entender como o JS lida com retornos de chamada e assincronicidade. (Isso é mesmo uma palavra?)
O Modelo de Loop e Concorrência de Eventos
Você precisa estar ciente de três coisas; A fila; o loop de eventos e a pilha
Em termos amplos e simplistas, o loop de eventos é como o gerente de projetos, está constantemente ouvindo todas as funções que desejam executar e se comunicar entre a fila e a pilha.
Depois de receber uma mensagem para executar algo, ela é adicionada à fila. A fila é a lista de itens que estão aguardando para serem executados (como sua solicitação AJAX). imagine assim:
Quando uma dessas mensagens é executada, ela aparece a mensagem da fila e cria uma pilha, a pilha é tudo que o JS precisa executar para executar a instrução na mensagem. Então, no nosso exemplo, está sendo dito para ligar
foobarFunc
Portanto, qualquer coisa que foobarFunc precise executar (no nosso caso
anotherFunction
) será empurrada para a pilha. executado e esquecido - o loop de eventos passará para a próxima coisa na fila (ou ouvirá mensagens)A principal coisa aqui é a ordem de execução. Isso é
QUANDO algo vai correr
Quando você faz uma chamada usando AJAX para uma parte externa ou executa qualquer código assíncrono (um setTimeout, por exemplo), o Javascript depende de uma resposta antes de prosseguir.
A grande questão é quando vai receber a resposta? A resposta é que não sabemos - então o loop de eventos está aguardando a mensagem dizer "ei, corra-me". Se o JS apenas esperasse por essa mensagem de forma síncrona, seu aplicativo congelaria e seria péssimo. Assim, o JS continua executando o próximo item na fila enquanto aguarda a inclusão da mensagem na fila.
É por isso que, com funcionalidade assíncrona, usamos itens chamados retornos de chamada . É como uma promessa literalmente. Como prometo retornar algo em algum momento, o jQuery usa retornos de chamada específicos chamados
deffered.done
deffered.fail
edeffered.always
(entre outros). Você pode vê-los todos aquiPortanto, o que você precisa fazer é passar uma função que promete executar em algum momento com os dados que são passados para ela.
Como um retorno de chamada não é executado imediatamente, mas posteriormente é importante passar a referência para a função, não executada. tão
então na maioria das vezes (mas nem sempre) você
foo
não passafoo()
Espero que isso faça algum sentido. Quando você encontra coisas como essa que parecem confusas - eu recomendo a leitura completa da documentação para pelo menos entender isso. Isso fará de você um desenvolvedor muito melhor.
fonte
Usando o ES2017, você deve ter isso como a declaração de função
E executando assim.
Ou a sintaxe da promessa
fonte