Подождите, чтобы вернуться из функции javascript до тех пор, пока не будет выполнено условие

Это странная проблема. У меня есть клиентский объект, который я создаю с помощью публичных/частных членов 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 возвращает значение true или нет для обоих логических флагов. Я бы использовал это с комбинацией setInterval, но я уверен, что это не сработает.

Поблагодарю ваши предложения.

Ответ 1

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

Что-то вроде этого:

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 отложенных:

$.when(jsonRequest1(), jsonRequest2()).then(done);

Ответ 2

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

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