Como retornar o valor de uma function de retorno de chamada assíncrona?

Esta pergunta é feita muitas vezes no SO. Mas ainda não consigo pegar coisas.

Eu quero obter algum valor de retorno de chamada. Veja o roteiro abaixo para esclarecimentos.

function foo(address){ // google map stuff geocoder.geocode( { 'address': address}, function(results, status) { results[0].geometry.location; // I want to return this value }) } foo(); //result should be results[0].geometry.location; value 

Se eu tentar retornar esse valor apenas ficando “indefinido”. Eu segui algumas ideias do SO, mas ainda falha.

Esses são:

 function foo(address){ var returnvalue; geocoder.geocode( { 'address': address}, function(results, status) { returnvalue = results[0].geometry.location; }) return returnvalue; } foo(); //still undefined 

Isso é impossível, pois você não pode retornar de uma chamada assíncrona dentro de um método síncrono.

Neste caso, você precisa passar um retorno de chamada para foo que receberá o valor de retorno

 function foo(address, fn){ geocoder.geocode( { 'address': address}, function(results, status) { fn(results[0].geometry.location); }); } foo("address", function(location){ alert(location); // this is where you get the return value }); 

O problema é que, se uma chamada de function interna é assíncrona, todas as funções que “envolvem” essa chamada também devem ser assíncronas para “retornar” uma resposta.

Se você tiver muitos callbacks, considere mergulhar e usar uma biblioteca de promises como Q.

Não faz sentido retornar valores de um retorno de chamada. Em vez disso, faça o trabalho “foo ()” que você deseja fazer dentro de seu callback.

Retornos de chamada asynchronouss são invocados pelo navegador ou por alguma estrutura, como a biblioteca de geocodificação do Google, quando os events ocorrem. Não há lugar para os valores retornados. Uma function de retorno de chamada pode retornar um valor, em outras palavras, mas o código que chama a function não prestará atenção ao valor de retorno.

Se acontecer de você estar usando jQuery, você pode querer dar um tiro: http://api.jquery.com/category/deferred-object/

Ele permite que você adie a execução da function de retorno de chamada até que a solicitação do ajax (ou qualquer operação assíncrona) seja concluída. Isso também pode ser usado para chamar um retorno de chamada assim que várias solicitações de ajax forem concluídas.