Отложенные вычисления в JavaScript
Ещё одна серия статей, на этот раз про отложенные вычисления. Описал, правда, не всё, что хотел, пара паттернов у самого ещё не уложились в голове.
В процессе написания сделал для себя небольшое (а может даже большое) открытие. Цитата:
|
мысли в слух ...
Цитата:
function f() {
var a = 1;
setTimeout('alert('+a+')', 2000);
}
f();
и тогда ошибки не будет. |
Можно, если только a -- значение примитивного типа.
|
http://alljs.ru/articles/timeout/overview.html
Цитата:
<script> (или каскада событий и обработчиков событий, в общем, «потока»).Вот тестовый пример, который работает идентично во всех браузерах, включая престарелый IE6
<a href="javascript:writeLog('click default action')" id="test">Клицк ми!</a>
<pre id="log"></pre>
<script>
setTimeout(function(){
writeLog("Log started"); /* а функция-то еще не определена! */
}, 0)
writeLog = function(str){
document.getElementById('log').innerHTML += str + "<br />";
};
test = document.getElementById("test");
test.onclick = function(){
writeLog('click event handler');
setTimeout(function(){
writeLog('timeout at click');
}, 0)
}
test.onmouseup = function(){
writeLog('mouseup event handler');
setTimeout(function(){
writeLog('timeout at mouseup');
}, 0)
}
</script>
А в IE setTimeout(…, 1) рискует превратиться в setTimeout(…, 18.2) из-за квантов таймера. |
subzey,
http://alljs.ru/articles/timeout/fast-settimeout.html В первом тесте меняю setTimeout(arguments.callee, 1);на setTimeout(arguments.callee, 0);Показания не изменяются. |
Хм, похоже на то.
Кстати, спасибо за эту тему, побенчмаркал Оперу 10.6 (Win) и получил странные результаты
var startTime = (new Date).getTime();
var i=0;
(function(){
if (++i>100){
alert((new Date).getTime() - startTime);
} else {
setTimeout(arguments.callee, 1E-80);
};
})()
Работает значительно быстрее, чем
var startTime = (new Date).getTime();
var i=0;
(function(){
if (++i>100){
alert((new Date).getTime() - startTime);
} else {
setTimeout(arguments.callee, 0);
};
})()
Подтвердите, или опревергните, плз. |
setZeroTimeout всё равно быстрее :)
|
setTimeout(function (a, b, c) { alert([a, b, c]); }, 10, "A", "B", "C")
Наверное, поэтому и не стали в других браузерах передавать числовой параметр, равный количеству миллисекунд, на которые запоздал вызов функции. |
Octane,
вобщем использовать это нельзя :) Хотя упомянуть стоит. |
По поводу передачи контекста и параметров в callback'и: можно добавить два отдельных метода в прототип функции, один для указания контекста, второй для передачи параметров. Например,
foo.of(this).pass(1, 2).defer(100); вместо foo.defer(100, this, [1, 2]); В результате не надо помнить порядок аргументов (по сути получаем именованные аргументы) и не надо пихать эти ctx, args во все остальные функции. Да и просто, у defer как-то многовато обязанностей иначе По поводу
(function() {
// Выполняем периодические действия
setTimeout(arguments.callee, 500);
})();
можно добавить еще один метод, например, periodical и писать как-нибудь вроде onTimer.periodical(500)(); Как передать в onTimer информацию - см. выше. Помимо вынесения "служебного" кода, передаваемые переменные будут явно обозначены (в отличие от варианта с замыканием) Цитата:
offtopic: код выглядит контрастно на фоне основного текста... |
Цитата:
Цитата:
Цитата:
Цитата:
Я стараюсь не вводить сущности без особой необходимости. defer упрощает жизнь, periodical -- нет. Цитата:
Цитата:
Ему может фон добавить, чтоб оттенял. |
var timerId;
element.onmouseover = function() {
timerId = setTimeout(function() {
alert(1);
}, 2000);
};
element.onmouseout = function() {
clearTimeout(timerId);
};
правильно так:
var timerId;
element.onmouseover = function() {
if( timerId ) return
timerId = setTimeout(function() {
alert(1);
}, 2000);
};
element.onmouseout = function() {
timerId = clearTimeout(timerId);
};
или так:
var timerId;
element.onmouseover = function() {
clearTimeout(timerId);
timerId = setTimeout(function() {
alert(1);
}, 2000);
};
element.onmouseout = function() {
clearTimeout(timerId);
};
|
касательно периодических вызовов, я делаю так:
var clock= Clock().latency( 5000 ).proc( function(){ alert(1) } ).active( true ) полученный таймер мы можем произвольно включать/выключать, менять период и вызываемую функцию. |
В общем разные у нас приоритеты, Kolyaj :) Я в первую очередь стараюсь убрать детали реализации, чтобы было видно что происходит, а не как это работает. А потом решаю проблемы с производительностью, если такие имеются. Потому что это упрощает мне жизнь. И поэтому количество оберток для меня не аргумент
Цитата:
Function.prototype.defer = function( timeout ){
var f = this;
return function(){
var actualFunc = f.of(this);
actualFunc = actualFunc.pass.apply(actualFunc, arguments);
setTimeout( actualFunc, timeout );
}
}
Цитата:
Цитата:
function onTimer(){
...
onTimer.stopPeriodical();
}
Цитата:
Цитата:
|
и еще...
первое событие timer в любом случае "пропадает"
Array.prototype.deferForEach = function(delay, fn, finish, scope) {
...
if (finish) {
finish.call(scope, this);
}
...
} else {
finish.call(scope, this); // finish вызывается, даже если не передан
}
};
то что нельзя создать два таймера, смещенных по времени - это by design? Просто я не сразу это осознал, несмотря на то, что прочитал "Для каждого интервала создает лишь один экземпляр таймера." Цитата:
|
.defer можно было бы чуть-чуть переписать, чтобы можно было передавать аргументы не в массиве.
foo.defer(100, this, 1, 2); вместо foo.defer(100, this, [1, 2]); |
Цитата:
Вообще, я ж с тобой не спорю. Я раньше точно так же рассуждал, поэтому понимаю твои доводы. Я не говорю, что ты потом будешь рассуждать как-то по другому, просто для меня вариант максимальной абстракции оказался неподходящим. Я ввожу готовые функции, если это 1. Добавляет кроссбраузерности, как например, addEventListener/attachEvent. 2. Сильно упрощает жизнь, как например XMLHttpRequest. Про Timer: основная его функция -- менеджить много таймеров. Т.е. если у тебя на странице будет несколько десятков независимых анимированных объектов, у каждого из которых свой setTimeout, всё будет слегка поттормаживать. А если сделать один setTimeout, который будет вызывать колбэки из каждого объекта, будет полегче. Цитата:
Ещё про тот файлик -- там deferForEach. Мне не нравится список аргументов, чтобы описывать его. Он перебирает элементы массива через заданные промежутки времени. Анимация им в две строчки делается. Цитата:
|
| Часовой пояс GMT +3, время: 10:41. |