У меня есть веб-приложение, где есть таймер, который постоянно считает в обратном порядке. Между тем клиент часто сверяется с сервером, чтобы видеть, было ли больше времени добавлено к таймеру. Кодекс выглядит примерно так:
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, Settimeate
, и т. Д.), Этот обратный вызов должен завершить выполнение выполнения, прежде чем можно назвать другой обратный вызов от другой операции ASYNC. Так что если работает обновление ()
, работает ни один другой JavaScript. Как только Обновление ()
Отделка, другие обратные вызовы от Async-операций могут быть уволены (например, Tick ()
). Интересно, что это также поэтому Settimeate
и его ILK не гарантированно выполнено в точном моменте, присвоенный тайм-ауту: какой-то другой JavaScript может быть заблокировать выполнение обратного вызова.
Проверьте http://ejohn.org/blog/how-javascript-timers-work/ Для какой-то хорошей информации о том, как все это работает.
До тех пор, пока вы добавляете еще несколько секунд до текущего времени, вы должны быть в порядке.
Вместо того, чтобы сделать время = NewTime;
попробуйте время + = NewTime;
Таким образом, вы не потеряете второе, вы беспокоитесь.
Тем не менее, вы теряете только секунду в худшем случае.
Я был неправ: это не решает проблему! (Объяснение после кода)
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;
};
Проблема с этим неправильным решением является то, что вы просто переместите проблему состояния гонки из вариабели
для переменной Newtime
.
Просто подумайте, что это: исполнение THIC
достигает и выполняет строку Time = NewTime;
Теперь, прежде чем продолжить, обновление звонится и Newime
значение x
. Теперь оформление тикания продолжается выполнение NewTime = false;
. Таким образом, вы потеряли x
значение Newime
и поэтому эффект вызова обновления ()!
JavaScript - это отдельная резьба. Там нет состояния расы. В JavaScript нет никаких способов Time = Newime;
и время - = 1;
для перекрытия во время выполнения. На самом деле, две функции гарантированно не перекрываются. Один из них будет бегать, а затем другой будет работать.
Проблема требует семафоров. Я делаю это часто за то, что посылаю семафоры после того, как предыдущий финиширует. Ваш случай немного похож ;)
Попробуйте что-нибудь подобное. Он должен игнорировать все попытки декремента времени, которые сталкиваются с обратным вызовом 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 в минуту ;)
.