Подождите, чтобы вернуться из функции JavaScript, пока не будет выполнено условие - PullRequest
10 голосов
/ 01 декабря 2011

Это странная проблема. У меня есть клиентский объект, который я создаю с использованием открытых / закрытых членов Crockford-esque:

var client = function() {
  var that, remote_data, other_data; 

  // add public interface
  that.doStuff = function(){...}

  // wait for remote resources to load
  remote_data = jsonRequest1();
  other_data  = jsonRequest2();

  return that;
};

Проблема, с которой я столкнулся, заключается в том, что мне нужно загрузить некоторые удаленные ресурсы JSON перед возвратом нового объекта «тот» (который сигнализирует о готовности клиента). Данные возвращаются асинхронно (очевидно), и я устанавливаю логические переменные, чтобы указать, когда каждый удаленный ресурс вернулся.

Я думал о том, чтобы сделать что-то вроде следующего:

return whenInitialized(function() { return that; });

Функция whenInitialized возвращает значение истинности обоих логических флагов. Я бы использовал это с комбинацией setInterval, но я уверен, что это не сработает.

Буду признателен за ваши предложения.

Ответы [ 2 ]

17 голосов
/ 01 декабря 2011

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

Примерно так:

var client = function(done) { // done is the callback
  var that, remote_data, other_data; 

  // add public interface
  that.doStuff = function(){...}

  // wait for remote resources to load
  var done1 = false, done2 = false;
  var complete1 = function() { done1 = true; if (done2) done(); };
  var complete2 = function() { done2 = true; if (done1) done(); };
  remote_data = jsonRequest1(complete1);
  other_data  = jsonRequest2(complete2);

  return that;
};

Но эти управляющие флаги действительно раздражают и не масштабируют.Лучший декларативный способ сделать это - использовать что-то вроде jQuery deferreds :

$.when(jsonRequest1(), jsonRequest2()).then(done);
1 голос
/ 01 декабря 2011

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

var syncRequest = function(options) {
    var is_finished = false;
    var result;
    var finished_callback = function(response) {
        is_finished = true;
        result = response.result;
    }

    ajax_request(options, finished_callback);

    // timeout in 30 seconds
    var timeout = (new Date()).getTime() + 30000;
    while ( !is_finished ) {
        if ( (new Date()).getTime() >= timeout ) {
            alert('Request timed out');
        }

        // do nothing, just block and wait for the request to finish
    }

    return result;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...