таймер JavaScript или интервалы, созданные в цикле с использованием замыкания - PullRequest
9 голосов
/ 21 июля 2010

Я использую jQuery для настройки таймера или интервального цикла для нескольких элементов, чтобы проверять их каждые пару секунд.Я попытался установить таймер и проверить, должен ли я его перезапустить, или установить и установить интервал и проверить, должен ли я его остановить.

Хотя это и упрощено, это в основном то, что мне нужно:

var mytimers = new Array();
$('div.items').each(function() {
    myID = $(this).attr('id');
    mytimers[myID] = setInterval( function() { myFunction(myID) } , 3000)
});
function myFunction(param) {
    alert(param);
    if (something()) {
        clearInterval(mytimers[param]);
    }
}

Идентификаторы для элементов класса: id_1, id_2, id_3.Но я просто получаю 3 оповещения, которые дают id_3.В своем коде я начал пытаться передать «this», но продолжал упрощать его, чтобы выяснить проблему.

Как мне заставить его каждый раз копировать переменную на новый адрес?Я знаю, что мне нужно использовать замыкания.Кажется, что он ссылается на другой var no mater what.

Я пытался упростить его до цикла с таймерами, например, так:

function tester(item) {
    return function() {
        alert(item);
    };
}
for(x=1;x<=3;x++) {
    setTimeout( '(function() { tester(x) })(x)' , 3000);
}

Но я думаю, что только усугубляю свою проблемуи это, похоже, ничего не делает.

Я искал предыдущие вопросы, но большинство заполнено тоннами дополнительного кода, а не сокращает его до конкретной проблемы и решается каким-то другим способом.Я хотел бы понять, как это работает лучше, если этот пример работает.При написании этого мне удалось выяснить, можно ли отключить таймер с помощью вспомогательной функции.

function tester(item)
    alert(item);
function myTimer(item)
    setInterval( function() { tester(item); }, 3000);
for(x=1;x<=3;x++)
    myTimer(item);

Как это можно сделать без этого?Есть какой-нибудь лучший способ?

Ответы [ 3 ]

4 голосов
/ 21 июля 2010

переменная myID локальна для анонимной функции,

var myID = $(this).attr('id');
3 голосов
/ 21 июля 2010

Когда вы используете каждый из них, вы находитесь в закрытом состоянии, вы просто забыли, что var делает вашу переменную приватной в области действия функции

var mytimers = new Array();
$('div.items').each(function() {
    **var** myID = $(this).attr('id'); 
    mytimers[myID] = setInterval( function() { myFunction(myID) } , 3000)
});
function myFunction(param) {
    alert(param);
    if (something()) {
        clearInterval(mytimers[param]);
    }
}
1 голос
/ 21 июля 2010

То есть вы хотите запускать myFunction на каждом из соответствующих элементов каждые три секунды?

Попробуйте это:

$('div.items').each( myFunction(this) );

var myFunction = function(elem) {
    return function() {
        if ( something(elem) ) {
            //return or do something with elem
        } else {
            window.setTimeout( myFunction(elem), 3000 );
        }
    }
};

Если условие в something() выполнено, то вы выполнили задание, если нет, то функция планирует запустить ее через 3 секунды с тем же элементом, что и раньше. Вы можете вызывать это столько раз, сколько хотите для разных элементов, каждый вызов имеет свой собственный elem.

Я предпочитаю передавать объекты наподобие elem и откладывать работу с их внутренностями до самого последнего момента. Пусть something() беспокоится об идентификаторе или о чем-то еще.

Никакой другой гимнастики с ассоциативным массивом (вместо new Array() вы могли бы просто использовать {}), или clearInterval, или ID не нужны.

Чтобы на самом деле обратиться к вашему решению, как сказал Marimuthu, вы оставили var вне объявления myID, что означает его глобальность и оно перезаписывается при каждой итерации. В результате, когда setInterval вызывает myFunction вместо получения уникального локального myID через замыкание, вы получаете глобальный, который уже был перезаписан в пустые времена.

...