LINUX.ORG.RU

Не понимаю JavaScript. Как сделать ожидание события загрузки данных?


0

1

Есть у меня «класс», у которого сделан метод init(). В нем происходит вызов метода load() для загрузки данных с сервера (по xmlrpc).

Задача: вызвать загрузку данных и дождаться результата. Если загрузка удачна - продолжить инит, если была ошибка - завершить инит.


// Глобальные переменные - статусы загрузки данных с сервера
var lb_load_status_ok=0;
var lb_load_status_in_process=1;
var lb_load_status_error=2;

...

function LBTeamData() 
{
 var loadStatus;

 this.init = function(id) 
 {
  // Загрузка с сервера информации
  this.load(id);
  
  // Ожидание завершения загрузки
  while( loadStatus==lb_load_status_in_process ){};

  // Если была ошибка  
  if(loadStatus==lb_load_status_error)
   return;
  
  // ... здесь продолжается инициализация ... 
 };
 

 this.load=function(teamId) 
 {
  loadStatus=lb_load_status_in_process;

  var that = this;

  // Получение данных о команде  
  $.xmlrpc({
        url: 'http://'+window.location.host+'/XmlRpcServer',
        methodName: 'getTeam',
        params: [teamId],
        success: function(response, status, jqXHR){ that.successLoad(response, status, jqXHR); },
        error: function(jqXHR, status, error) { that.errorLoad(jqXHR, status, error); }
  });

 };


 // Обработчик получения данных
 this.successLoad=function(response, status, jqXHR) 
 {
  loadStatus=lb_load_status_ok;

  name=response[0]['name']; // Название команды
  unitsNames=response[0]['unitsNames']; // Имена игроков

  alert("Success load data from server");
 };


 // Обработчик ошибки при получения данных
 this.errorLoad=function(jqXHR, status, error) 
 {
  loadStatus=lb_load_status_error;

  alert("Error at getting team data from server: "+error);
 };

}

Проблема в строке с циклом while(). На нем скрипт затыкается как на бесконечном цикле.

Если его убрать, то через некоторое время появится сообщение «Success load data from server». Это свидетельствует о том, что данные в подгружаются нормально.

Но я не могу понять, как в «линейном» коде метода init() дождаться появления этих данных. Флаги не помогают. Встраивать обработчики прямо в «линейный» код как лямбды - это издевательство, код получает рваный и плохо сопровождаемый.

Вопрос. Почему не работает этот кусок кода? Почему в цикле while() не отслеживаетс изменение свойства loadStatus? Как сделать чтоб отслеживалось?

★★★★★

учи жаваскрипт. тебе не надо делать свой event loop, ты уже находишься внутри него. и все принято (и удобнее \ безопаснее) делать асинхронно.

wwwsevolod
()
Последнее исправление: wwwsevolod (всего исправлений: 1)
Ответ на: комментарий от wwwsevolod

так же там есть событие onreadystatechange, через который можно сделать то что ты хочешь, которое может кинуть объект класса XMLHttpRequest.

читай хотя бы справочник: http://help.dottoro.com/ljspgwvf.php

wwwsevolod
()
Ответ на: комментарий от wwwsevolod

тебе не надо делать свой event loop, ты уже находишься внутри него. и все принято (и удобнее \ безопаснее) делать асинхронно.

Так я не понимаю, как сделать асинхронно.

Вызов successLoad() или errorLoad() происходит асинхронно. Пока они не вызваны (какой-то один из них) - продолжать дальше инит нельзя.

Вопрос. Как дождаться завершения этих асинхронных событий?


onreadystatechange, через который можно сделать то что ты хочешь, которое может кинуть объект класса XMLHttpRequest.

Я же написал, что делаю все через xmlrpc. Использую реализацию на jQuery (ведь ты заметил $, не так ли?). Там XMLHttpRequest скрыт за интерфейсом. И никакого onreadystatechange нет.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

1) $ не означает jQuery, это может быть zepto, это может быть prototype и еще некоторое количество.

2) методы jquery работающие с сетью возвращают объект класса Deferred, у которого можно повесить колбэк на done и error, например. http://api.jquery.com/jQuery.ajax/

3) во вторых ты можешь слушать изменения статус кода на нужное тебе (см. ссылку выше ctr+f «statusCode»)

4) success и error будут вызваны в конце запроса - т.е. когда будут получены соответсвующие заголовки. и success отработает ровно там где тебе надо, и еррор соответсвенно тоже, тебе не нужно самому делать проверки, но если очень хочется - используй complete вместо их обоих.

ты что то не так делаешь)

wwwsevolod
()

Но я не могу понять, как в «линейном» коде метода init() дождаться появления этих данных.

Никак, поток один и он занят циклом. Обработчик success не может выполниться.

Ничего страшного в дроблении нет. Будет у тебя цепочка функций вместо одной и ничего страшного. На входе в неё передаёшь колбек на error как в том же xmlrpc, между частями error и ссылку на следующую требуемую функцию всё.

ollowtf ★★★
()
Последнее исправление: ollowtf (всего исправлений: 1)
Ответ на: комментарий от ollowtf

Ничего страшного в дроблении нет. Будет у тебя цепочка функций вместо одной и ничего страшного. На входе в неё передаёшь колбек на error как в том же xmlrpc, между частями error и ссылку на следующую требуемую функцию всё.

Я понял вас, но остался вот какой вопрос.

Предположим, переделал я LBTeamData.init() на цепочку вызовов:

this.init = function(id) 
 {
  // Загрузка с сервера информации
  this.load(id, this.init_second_callback() );
 }

this.init_second_callback = function() 
 {
  // Тут еще какие-то действия, еще какая-то подгрузка информации  
  this.loadFormula(id, this.init_third_callback() );
 }

this.init_third_callback = function() 
 {
  // Тут инит наконец-то завершен
  ...
 }

В load() и loadFormula(), точнее, в обработчиках событий получения данных, сделаны вызовы коллбаков. Все вроде понятно.

Однако помимо этого класса существует вышестоящий класс, который и вызывает инит экземпляра этого класса. И он тоже должен дождаться пока данный класс проинитится, перед тем как инитить следующие объекты.

Это что же получается, что и в вышестоящем классе надо все переделывать на цепочку функций, чтобы дожидаться инита вызываемого объекта?

Xintrea ★★★★★
() автор топика

В js так не правильно:

action1();
action2();
action3();

Правильно так:

action1({success: action2});
action2({success: action3});
action3();

Ну ты понел.

А вообще для ajax-запросов можно установить параметр sync, тогда будет работать и первый вариант. Но так делать не Ъ - если браузер ждет завершения этого скрипта для показа страницы, то юзер может прождать довольно долго.

anonymous
()
Ответ на: комментарий от Xintrea

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

wwwsevolod
()
Ответ на: комментарий от wwwsevolod

когда ты хочешь передать функцию как аргумент а не результат который она возвращает, передавать её надо без вызывающих скобочек

Простой вопрос. А как вызвать коллбек-функцию с аргументами?

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

аргументы передаются там где она вызывается, соотвественно куда ты передал функцию, там и аргументы будут передавать автоматически

если тебе нужны «свои» аргументы то

1) они тебе не нужны ведь есть замыкания, т.е. переменные доступны из областей видимости находящихся вне функции т.е. var a = 1; (function() { a = 2 })() alert(a) выведет 2

2) если уж сильно хочется аргументами то: var context = this; //для наглядности var cb = function(arg1, arg2, arg3 /** your arguments */, jqxhr /**default argument of ajax functions */) { // и при вызове функции в нее автоматом будут переданы аргументы которые ты забиндил }.bind(context, 1, 2, 3); в bind первым аргументом идет контекст вызова (т.е. нужный this) аналог с jQuery, для кроссбраузерности: var cb = jQuery.proxy(function(arg1, arg2, arg3, jqxhr) { //тоже самое }, context, 1, 2, 3);

wwwsevolod
()
Ответ на: комментарий от Xintrea

А как вызвать коллбек-функцию с аргументами?

Через замыкания:

function Event(var1, var2) {
  return function embedded() {
    alert('Переданы: var1=' + var1 + ' и var2=' + var2);
  }
}

и дальше назначаем обработчик события как результат выполнения функции Event с переданными параметрами.

Wizard_ ★★★★★
()

То, что ты хочешь сделать, реализуется с помощью continuations. В JavaScript их поддержки нет и, насколько мне известно, сэмулировать не получится.

Legioner ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.