Мастер-классы по Javascript, AJAX/COMET, jQuery Узнать больше...
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 за очень дельный совет.

+4

Автор: Dmitry A. Soshnikov, дата: 19 ноября, 2009 - 15: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 - 15:50
#permalink

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


Автор: Dmitry A. Soshnikov, дата: 19 ноября, 2009 - 19: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 - 18:50
#permalink

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


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

А проверить?


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

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

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


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

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


Автор: Dmitry A. Soshnikov, дата: 22 января, 2010 - 01: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 - 14:03
#permalink

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

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

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

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


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

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

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


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

Приветствуются комментарии:
  • Полезные.
  • Дополняющие прочитанное.
  • Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
    Для остальных вопросов и обсуждений есть форум.
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
Антиспам
3 + 1 =
Введите результат. Например, для 1+3, введите 4.
 
Поиск по сайту
Другие записи этого автора
subzey
Вакансии
Содержание

Учебник javascript

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

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

Интерфейсы

Все об AJAX

Оптимизация

Разное

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

Статьи и мероприятия

Будьте в курсе наших последних новостей!

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