Вопрос

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

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

Спасибо.

Это было полезно?

Решение

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

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

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

Другие советы

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

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

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()!

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top