Как вернуть значение из асинхронной функции обратного вызова?

Этот вопрос задается много раз в SO. Но все же я не могу получить материал.

Я хочу получить некоторую ценность от обратного вызова. Посмотрите на script ниже для уточнения.

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

Если я попытаюсь вернуть это значение, просто получив "undefined". Я следил за некоторыми идеями из SO, но все еще не удается.

Это:

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

Ответ 1

Это невозможно, так как вы не можете вернуться из асинхронного вызова внутри синхронного метода.

В этом случае вам нужно передать обратный вызов foo, который получит возвращаемое значение

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
});

Дело в том, что если внутренний вызов функции асинхронен, то все функции "обертывания" этого вызова также должны быть асинхронными, чтобы "вернуть" ответ.

Если у вас много обратных вызовов, вы можете подумать о том, чтобы сделать погружение и использовать библиотеку обещаний например Q.

Ответ 2

Нет смысла возвращать значения из обратного вызова. Вместо этого выполните "foo()" работу, которую вы хотите сделать внутри, ваш обратный вызов.

Асинхронные обратные вызовы вызываются браузером или некоторыми фреймворками, такими как библиотека геокодирования Google, когда происходят события. Там нет места для возвращаемых ценностей. Функция обратного вызова может вернуть значение, другими словами, но код, вызывающий функцию, не будет обращать внимание на возвращаемое значение.

Ответ 3

Если вы используете jQuery, вы можете сделать это: http://api.jquery.com/category/deferred-object/

Это позволяет отложить выполнение функции обратного вызова до тех пор, пока не будет выполнен запрос ajax (или любая операция async). Это также можно использовать для вызова обратного вызова, как только несколько запросов ajax завершены.