Javascript.RU

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 за очень дельный совет.

+6

Автор: Dmitry A. Soshnikov, дата: 19 ноября, 2009 - 14:45
#permalink

В Firefox, в setTimeout первым аргументом передаётся "просроченное время", "задержка" (если таковые возникнут) в ходе интерпретации кода. Т.е., если setTimeout не успевает запуститься после назначенного времени (например, через 100мс), эта "просроченная задержка" фиксируется первым параметром.

Далее, когда поток освободился и готов принять (вклинить) код setTimeout-a, проверяется, есть ли "просроченное время", и если есть, то код может выполнится моментально (проверить можно, если поставить alert сразу после вызова setTimeout-a и подождать некоторое время, превышающее интервал таймаута).

Простой пример:

setTimeout(function () {
    alert(arguments[0]); // ah? ;)
}, 0);

Или даже так (чтобы приблизать к Вашему случаю):

setTimeout(function (myParam) {
    alert(myParam); // wth? ;)
}, 0);

Почитать можно в багтреккере:

https://bugzilla.mozilla.org/show_bug.cgi?id=10637
https://bugzilla.mozilla.org/show_bug.cgi?id=263945


Автор: subzey, дата: 19 ноября, 2009 - 14:50
#permalink

Спасибо, значение параметра посмотреть я как-то не догадался, ограничился typeof Unsure. Пожалуй, нужно переписать половину поста.
Но, в самом деле, действительно ли нужен этот параметр?


Автор: Dmitry A. Soshnikov, дата: 19 ноября, 2009 - 18:33
#permalink

Но, в самом деле, действительно ли нужен этот параметр?

Не думаю. В первой ссылке там в багтреккере тоже разборки, надо ли это фиксить (ещё 10 лет назад )? Мотивировали обратной совместимостью с Netscape 4.X, но это бред какой-то (на сегодняшний день имеется в виду, поскольку этот скрытый параметр задержки остался до сих пор).

С другой стороны, как должен себя вести следующий код, в случае, если оставить alert(1) на 3-4 секунды:

setTimeout(function (param) {
  alert(param);
}, 3000);
alert(1);

По идее, запрашивалось отложенное выполнение через 3 секунды (3000 миллисекунд). Второй alert отнял это время, блокируя поток. После того, как мы уничтожим alert(1), начинает работать функция setTimeout-a.

И на сегодня, во всех браузерах, кроме FF и Opera, начинается отсчёт 3000 миллисекунд (потестируйте, например, в IE или Chrome, Safari) после alert(1) (вероятно, мотивируя тем, что alert, уж точно, полностью блокирует поток и ничего выполняться не может). FF и Opera, в свою очередь, определяют это просроченное время и сокращают таймаут (в случае, если таймаут просрочен полностью, функция выполняется сразу). Поведение последних кажется более правильным (даже несмотря на полную блокировку alert-ом).

Только в Opera, в отличие от FF, не передаётся никакой параметр, портя пользовательскую функцию.

Моё мнение, зря они оставили этот параметр (явно, грязный хак просто был, и лень было фиксить потом), надо было его убрать ещё тогда, 10 лет назад.


Автор: lazyday, дата: 9 декабря, 2009 - 17:50
#permalink

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


Автор: Dmitry A. Soshnikov, дата: 17 декабря, 2009 - 12:04
#permalink

А проверить?


Автор: Cross (не зарегистрирован), дата: 24 декабря, 2009 - 15:57
#permalink

Мне кажется чувак не понял фразу
>В Firefox, в setTimeout первым аргументом передаётся "просроченное время"

Он имел ввиду последним аргументом в setTimeout(function, delay), а ты же говорил про то, что это сам setTimeout потом вызывает функцию, передавая в неё первым аргументом это самое просроченное время


Автор: Гость (не зарегистрирован), дата: 4 января, 2010 - 23:56
#permalink
function f (x, y) { alert (x+":"+y); }
setTimeout (f, 0, 20);
alert (0);

алерт покажет что-нибудь вроде 20:xxxx
так что таки последним


Автор: Dmitry A. Soshnikov, дата: 22 января, 2010 - 00:41
#permalink

А дополнительные параметры в setTimeout (которые не везде и работают) не рассматривались. Впрочем, и там - не последним (но, и не всегда первым):

function f(x, y, z) { alert(x + ":" + y); }
setTimeout(f, 0, 20);
alert(0);
function f(x, y, z) { alert(x + ":" + y); }
setTimeout(f, 0);
alert(0);

Автор: Гость (не зарегистрирован), дата: 24 января, 2010 - 13:03
#permalink

А дополнительные параметры в setTimeout (которые не везде и работают) не рассматривались. Впрочем, и там - не последним (но, и не всегда первым):

setTimeout(f, 0, 20); передаст первым аргументом 20, вторым и последним - задержку.

setTimeout(f, 0); передаст первым и последним аргументом задержку.

А вот в функции f задержка может и не оказаться на месте последнего аргумента.


Автор: Dmitry A. Soshnikov, дата: 24 января, 2010 - 22:35
#permalink

А вот в функции f задержка может и не оказаться на месте последнего аргумента.

Наибольший интерес как раз и представляет функция f и положение параметра задержки в числе её параметров.


Автор: Гость (не зарегистрирован), дата: 22 декабря, 2010 - 16:37
#permalink

Когда делаешь часики на js, этот параметр очень полезен. Иначе, через пол часа может появиться отставание на минуту.

Есть ли решение данной проблемы для других браузеров?


Автор: B@rmaley.e><e, дата: 22 декабря, 2010 - 20:13
#permalink

Вы неправильно делаете эти самые часики. Вам нужно каждую секунду получать системное время, а не рассчитывать на то, что прошла именно 1 секунда с прошлого вызова.


Автор: Гость (не зарегистрирован), дата: 23 декабря, 2010 - 11:16
#permalink

Мне нужно было показывать московское время независимо от местоположения пользователя.
Тут возникает только одна идея: вначале брать время с сервера и вычислять его разницу с пользовательским. А потом эту разницу каждый раз отнимать (прибавлять) от пользовательского времени.
Возможно, и не самое плохое решение. Зря на него грешил


Автор: edd_k, дата: 21 февраля, 2011 - 04:36
#permalink

Московское время - это +3 GMT
У пользователя в объекте Date получаете не локальное, а GMT время, прибавляете 3 часа и радуетесь. Это то, что касается местоположения пользователя и часовых поясов.

Периодический прием времени с сервера позволяет кроме этого нивелировать неточность часов пользователя. Но вовсе не для вычисления разницы часовых поясов используется.

А вот отсчитывать количество секунд по количеству срабатываний таймера - это в любом случае не приемлимый вариант. Даже если есть парамер "просрочки" этих событий. Никогда не понимал, почему людям в голову приходит именно такая идея. Часы отображают время. Время - это Date. Таймер же - это механизм, позволяющий периодически что-то делать. Например перерисовывать часы. Но не быть же источником времени!


Автор: Гость (не зарегистрирован), дата: 16 апреля, 2022 - 00:47
#permalink

Автор: Гость (не зарегистрирован), дата: 16 апреля, 2022 - 13:11
#permalink

Отправить комментарий

Приветствуются комментарии:
  • Полезные.
  • Дополняющие прочитанное.
  • Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
    Для остальных вопросов и обсуждений есть форум.
P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью.
Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Разрешены HTML-таги: <strike> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <u> <i> <b> <pre> <img> <abbr> <blockquote> <h1> <h2> <h3> <h4> <h5> <p> <div> <span> <sub> <sup>
  • Строки и параграфы переносятся автоматически.
  • Текстовые смайлы будут заменены на графические.

Подробнее о форматировании

CAPTCHA
Антиспам
7 + 4 =
Введите результат. Например, для 1+3, введите 4.
 
Поиск по сайту
Другие записи этого автора
subzey
Содержание

Учебник javascript

Основные элементы языка

Сундучок с инструментами

Интерфейсы

Все об AJAX

Оптимизация

Разное

Дерево всех статей

Популярные таги
Последние комментарии
Последние темы на форуме
Forum