Подтвердить что ты не робот

Ajax concurrency

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

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, чтобы понять, как справиться с этой проблемой concurrency: есть ли простой способ сделать это, или если нет, может кто-нибудь указать мне на ресурсы, где я могу научиться больше?

Спасибо.

4b9b3361

Ответ 1

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

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

Ознакомьтесь с http://ejohn.org/blog/how-javascript-timers-work/ за хорошую информацию о том, как все это работает.

Ответ 2

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

Ответ 3

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

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 get called и NEWTIME получает значение X. Теперь выполнение тика продолжается выполнение NEWTIME = false;. Таким образом, вы потеряли значение X NEWTIME и, следовательно, эффект вызова update()!

Ответ 4

Проблема требует некоторых семафоров. Я делаю это много для отправки 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 в минуту;)

Ответ 5

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

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

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