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

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

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

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

3 ответа

Решение

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

В этом случае вам нужно передать обратный вызов в 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.

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

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

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

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

Другие вопросы по тегам