Firefox и setTimeout
При запуске функции в Firefox через setTimeout ей передается дополнительный параметр — время, на которое было просрочено выполнение кода.
Иногда это может привести к неожиданным последствиям, будьте осторожны, граждане!
var testFunction = function(p){
…
setTimeout(arguments.callee, n);
…
}
Через n миллисекунд будет вызвано в Firefox:
testFunction(p)
, в остальных браузерах:
testFunction() .
Такое нелогичное отличие достаточно неприятно, и у меня лично привело к выпадению из функции по return в совершенно неожиданном месте. Хотя, профессионалы, наверное, объяснят мне, в чем я неправ.
А вот и полный пример:
var testFunction = function(p){
// свойство функции: сколько раз уже была вызвана
if (!arguments.callee.runTimes) arguments.callee.runTimes = 0;
arguments.callee.runTimes++;
// алерт с отладочной информацией
alert("Function called " + arguments.callee.runTimes + " time.\r\nParameters are " + ((typeof (p) == "undefined")?"not ":"") + "set.");
// если запущено менее двух раз (нам же не нужно зацикливание?)
if (arguments.callee.runTimes < 2){
// запускаем себя же через какое-то время
setTimeout(arguments.callee, 100);
}
};
// вызов функции напрямую
testFunction("some string parameter");
Спасибо Dmitry A. Soshnikov за очень дельный совет.
|
В Firefox, в setTimeout первым аргументом передаётся "просроченное время", "задержка" (если таковые возникнут) в ходе интерпретации кода. Т.е., если setTimeout не успевает запуститься после назначенного времени (например, через 100мс), эта "просроченная задержка" фиксируется первым параметром.
Далее, когда поток освободился и готов принять (вклинить) код setTimeout-a, проверяется, есть ли "просроченное время", и если есть, то код может выполнится моментально (проверить можно, если поставить alert сразу после вызова setTimeout-a и подождать некоторое время, превышающее интервал таймаута).
Простой пример:
Или даже так (чтобы приблизать к Вашему случаю):
Почитать можно в багтреккере:
https://bugzilla.mozilla.org/show_bug.cgi?id=10637
https://bugzilla.mozilla.org/show_bug.cgi?id=263945
Спасибо, значение параметра посмотреть я как-то не догадался, ограничился
typeof
. Пожалуй, нужно переписать половину поста.Но, в самом деле, действительно ли нужен этот параметр?
Не думаю. В первой ссылке там в багтреккере тоже разборки, надо ли это фиксить (ещё 10 лет назад )? Мотивировали обратной совместимостью с Netscape 4.X, но это бред какой-то (на сегодняшний день имеется в виду, поскольку этот скрытый параметр задержки остался до сих пор).
С другой стороны, как должен себя вести следующий код, в случае, если оставить alert(1) на 3-4 секунды:
По идее, запрашивалось отложенное выполнение через 3 секунды (3000 миллисекунд). Второй alert отнял это время, блокируя поток. После того, как мы уничтожим alert(1), начинает работать функция setTimeout-a.
И на сегодня, во всех браузерах, кроме FF и Opera, начинается отсчёт 3000 миллисекунд (потестируйте, например, в IE или Chrome, Safari) после alert(1) (вероятно, мотивируя тем, что alert, уж точно, полностью блокирует поток и ничего выполняться не может). FF и Opera, в свою очередь, определяют это просроченное время и сокращают таймаут (в случае, если таймаут просрочен полностью, функция выполняется сразу). Поведение последних кажется более правильным (даже несмотря на полную блокировку alert-ом).
Только в Opera, в отличие от FF, не передаётся никакой параметр, портя пользовательскую функцию.
Моё мнение, зря они оставили этот параметр (явно, грязный хак просто был, и лень было фиксить потом), надо было его убрать ещё тогда, 10 лет назад.
просроченное время передается не первым, а последним аргументом
А проверить?
Мне кажется чувак не понял фразу
>В Firefox, в setTimeout первым аргументом передаётся "просроченное время"
Он имел ввиду последним аргументом в
setTimeout(function, delay)
, а ты же говорил про то, что это самsetTimeout
потом вызывает функцию, передавая в неё первым аргументом это самое просроченное времяалерт покажет что-нибудь вроде 20:xxxx
так что таки последним
А дополнительные параметры в setTimeout (которые не везде и работают) не рассматривались. Впрочем, и там - не последним (но, и не всегда первым):
А дополнительные параметры в setTimeout (которые не везде и работают) не рассматривались. Впрочем, и там - не последним (но, и не всегда первым):
setTimeout(f, 0, 20); передаст первым аргументом 20, вторым и последним - задержку.
setTimeout(f, 0); передаст первым и последним аргументом задержку.
А вот в функции f задержка может и не оказаться на месте последнего аргумента.
Наибольший интерес как раз и представляет функция f и положение параметра задержки в числе её параметров.
Когда делаешь часики на js, этот параметр очень полезен. Иначе, через пол часа может появиться отставание на минуту.
Есть ли решение данной проблемы для других браузеров?
Вы неправильно делаете эти самые часики. Вам нужно каждую секунду получать системное время, а не рассчитывать на то, что прошла именно 1 секунда с прошлого вызова.
Мне нужно было показывать московское время независимо от местоположения пользователя.
Тут возникает только одна идея: вначале брать время с сервера и вычислять его разницу с пользовательским. А потом эту разницу каждый раз отнимать (прибавлять) от пользовательского времени.
Возможно, и не самое плохое решение. Зря на него грешил
Московское время - это +3 GMT
У пользователя в объекте Date получаете не локальное, а GMT время, прибавляете 3 часа и радуетесь. Это то, что касается местоположения пользователя и часовых поясов.
Периодический прием времени с сервера позволяет кроме этого нивелировать неточность часов пользователя. Но вовсе не для вычисления разницы часовых поясов используется.
А вот отсчитывать количество секунд по количеству срабатываний таймера - это в любом случае не приемлимый вариант. Даже если есть парамер "просрочки" этих событий. Никогда не понимал, почему людям в голову приходит именно такая идея. Часы отображают время. Время - это Date. Таймер же - это механизм, позволяющий периодически что-то делать. Например перерисовывать часы. Но не быть же источником времени!
Roksa trzebnica
Roksa trzemeszno
Отправить комментарий
Приветствуются комментарии:Для остальных вопросов и обсуждений есть форум.