Ajax параллелизм - PullRequest
       6

Ajax параллелизм

16 голосов
/ 16 января 2010

У меня есть веб-приложение, в котором есть таймер, который постоянно ведет обратный отсчет. Тем временем клиент часто проверяет сервер, чтобы узнать, было ли добавлено больше времени к таймеру. Код выглядит примерно так:

function tick() {
    // This function is called once every second
    time -= 1;
    redisplay(time);
};
function update(newtime) {
    // This function is called whenever the ajax request
    // to the server yields a new time
    time = newtime;
};

Конечно, это немного сложнее, но вы можете видеть внутреннее состояние расы. Что, если обновление и функция галочки одновременно пытаются изменить time?

Честно говоря, я не знаю почти достаточно javascript, чтобы понять, как справиться с такой проблемой параллелизма: есть ли простой способ сделать это, или если нет, может кто-нибудь указать мне ресурсы, где я могу узнать больше?

Спасибо.

Ответы [ 5 ]

16 голосов
/ 16 января 2010

У вас нет состояния гонки, потому что Javascript не выполняется одновременно.

Каждый раз, когда выполняется обратный вызов из асинхронной операции (AJAX, setTimeout и т. Д.), Этот обратный вызов должен завершиться, прежде чем может быть вызван другой обратный вызов из другой асинхронной операции. Так что если update() запущен, другой Javascript не работает. После завершения update() могут быть запущены другие обратные вызовы от асинхронных операций (например, tick()). Интересно, что именно поэтому setTimeout и тому подобное не гарантированно выполнятся в тот момент, когда истечет время ожидания: некоторый другой javascript может блокировать выполнение обратного вызова.

Проверьте http://ejohn.org/blog/how-javascript-timers-work/ для некоторой хорошей информации о том, как все это работает.

8 голосов
/ 16 января 2010

Javascript является однопоточным. Здесь нет условий гонки. В javascript нет способа перекрытия двух строк time = newtime; и time -= 1; во время выполнения. На самом деле, две функции гарантированно не перекрываются. Один из них будет работать, а затем другой.

0 голосов
/ 16 января 2010

Я ошибся: это не решает проблему! (объяснение после кода)

NEWTIME = false;
function tick() {
    // This function is called once every second
    if (NEWTIME) {
        time = NEWTIME;
        NEWTIME = false;
    }
    time -= 1;
    redisplay(time);
};
function update(newtime) {
    // This function is called whenever the ajax request
    // to the server yields a new time
    NEWTIME = newtime;
};

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

Только подумайте: выполнение tick достигает и выполняет строку time = NEWTIME;, теперь перед продолжением вызывается update, и NEWTIME получает значение X. Теперь выполнение тика продолжается NEWTIME = false;. Таким образом, вы потеряли X значение NEWTIME и, следовательно, эффект вызова update ()!

0 голосов
/ 16 января 2010

Для проблемы нужны семафоры. Я делаю это много для отправки ajax после завершения предыдущего. Ваш случай немного похож;)

Попробуйте что-нибудь подобное. Он должен игнорировать все попытки уменьшить время, которые сталкиваются с обратным вызовом ajax.

window.TimeKeeper = new function(){
this.time=0; //initial value, whatever
this.isopen=true;

this.decrement = function(){ 
 if(this.isopen){
  this.time--;
  redisplay(this.time);
  }
 }
this.set = function(val){
 if(this.isopen){
  this.isopen=false;
  this.time=val;
  this.isopen=true;
  } else {
  //another AJAX callback is modifying time. 
   //You can enqueue current value and put it later
  }
 }

}

function tick() {
    TimeKeeper.decrement();

};
function update(newtime) {
    TimeKeeper.set(newtime);
};

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

И один маленький совет - избегайте слишком частых запросов к AJAX - это может вызвать дополнительные проблемы - например, запросы возвращаются в другом порядке, нежели отправленные, и использование памяти Firefox слишком сильно увеличивает количество ajax в минуту;)

0 голосов
/ 16 января 2010

Пока вы добавляете еще несколько секунд к вашему текущему времени, с вами все будет в порядке.

Вместо time = newtime; попробуйте time += newtime; Таким образом, вы не потеряете секунду, о которой беспокоитесь.

Тем не менее, в худшем случае вы теряете секунду.

...