Во-первых, настоятельно рекомендуется, чтобы вы указали обратный вызов (function
) в качестве первого аргумента, а не строку, потому что эта строка оценивается в глобальной области видимости, и мы все знаем, что плохие вещи случаются, когда мы используем eval
в js (связанный eval post: Когда JavaScript eval () не злой? ).
Итак, ваш
setInterval("b()", 1000);
следует переписать как:
setInterval(b, 1000);
или:
setInterval(function() { b(); }, 1000);
Я также рекомендую использовать setTimeout
для имитации setInterval
.
Основным недостатком функции setInterval
является то, что она выполняет блок кода каждые n
миллисекунд, независимо от выполнения предыдущего блока кода.
Поэтому, если по какой-то причине обратный вызов setInterval
выполняется дольше, чем предоставленная задержка, это вызовет некоторые переполнения стека .
Для примера возьмем следующий код:
function foo() {
// this takes about 2 seconds to execute
// .. code here
}
setInterval(foo, 1000);
Это фактически остановит браузер, потому что он будет выполнять foo
(почти) бесконечное количество раз, но никогда не завершит его.
Решение в этом случае состоит в том, чтобы эмулировать setInterval
с setTimeout
, чтобы гарантировать, что обратный вызов завершился, прежде чем вызывать его снова:
function foo() {
// this takes about 2 seconds to execute
// .. code here
}
function newSetInterval(callback, duration, callbackArguments) {
callback.apply(this, callbackArguments);
var args = arguments,
scope = this;
setTimeout(function() {
newSetInterval.apply(scope, args);
}, duration);
}
newSetInterval(foo, 1000);
Теперь foo
вызывается снова только после того, как предыдущий экземпляр завершил выполнение кода.
Я бы применил то же самое к вашему коду, чтобы позволить браузеру решить, когда он может выполнить код, а не заставлять его выполнять блок кода, если он в данный момент занят или нет:
function a() {
newSetInterval(b, 1000);
updateText("still working");
}
function b() {
timer++;
updateText(timer);
}
function newSetInterval(callback, duration, callbackArguments) {
callback.apply(this, callbackArguments);
var args = arguments,
scope=this;
setTimeout(function() {
newSetInterval.apply(scope, args);
}, duration);
}
Если вам интересно, я переписал функции setInterval
и clearInterval
, чтобы использовать их где угодно, не заботясь о переполнениях стека:
function setInterval(f, time) {
setInterval.ids = setInterval.ids || {};
setInterval.idCount = setInterval.idCount || 0;
var that = this,
id = setInterval.idCount++,
// to prevent firefox bug that adds an extra element to the arguments
l = arguments.length - 2;
(function theFn() {
// to prevent firefox bug that adds an extra element to the arguments
var args = [].slice.call(arguments, 0, l);
f.apply(this, args);
setInterval.ids[id] = setTimeout.apply(this, [theFn, time].concat(args));
}).apply(that, [].slice.call(arguments, 2, arguments.length));
return id;
}
function clearInterval(id) {
if(!setInterval.ids || !setInterval.ids[id]) {
return false;
}
clearTimeout(setInterval.ids[id]);
return true;
}