Наблюдение за циклами setTimeout, так что одновременно работает только один - PullRequest
2 голосов
/ 29 апреля 2010

Я создаю ротатор контента в jQuery. Всего 5 предметов. Элемент 1 появляется, приостанавливается на 10 секунд, затем исчезает, а затем - элемент 2. Повтор.

Достаточно просто. Используя setTimeout, я могу вызвать набор функций, которые создают цикл и будут повторять процесс бесконечно.

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

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

Проблема, с которой я столкнулся, заключалась в том, как на самом деле пропинговать переменную через таймер. Решение состоит в том, чтобы погрузиться в замыкания JavaScript ... которые немного над моей головой, но определенно мне нужно углубиться в большее.

Однако в процессе этого я предложил альтернативную опцию, которая на самом деле кажется более эффективной в плане производительности (по крайней мере, теоретически). У меня есть образец, работающий здесь:

http://jsbin.com/uxupi/14

(он использует console.log, поэтому включите fireBug)

Пример сценария:

$(document).ready(function(){

var loopCount = 0;

$('p#hello').click(function(){
  loopCount++;
  doThatThing(loopCount);
})

function doThatOtherThing(currentLoopCount) {  
console.log('doThatOtherThing-'+currentLoopCount);
if(currentLoopCount==loopCount){
  setTimeout(function(){doThatThing(currentLoopCount)},5000)
 }
}  


function doThatThing(currentLoopCount) {
 console.log('doThatThing-'+currentLoopCount);
 if(currentLoopCount==loopCount){
   setTimeout(function(){doThatOtherThing(currentLoopCount)},5000);
 }
}

}) 

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

Каждый щелчок триггера также увеличивает глобальную переменную, так что последующие вызовы цикла имеют уникальную локальную переменную.

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

Мысли об этом? Правильное решение? Лучшие варианты? Предостережения? Опасности?

UPDATE:

Я использую предложенное Джоном предложение через опцию clearTimeout.

Однако я не могу заставить его работать. Логика такова:

var slideNumber = 0; 

var timeout = null;


function startLoop(slideNumber) {
    //... code is here to do stuff here to set up the slide based on slideNumber...
    slideFadeIn()
}

function continueCheck() {
    if (timeout != null) {
        // cancel the scheduled task.
        clearTimeout(timeout);
        timeout = null;
        return false;
    } else {
        return true;
    }
};

function slideFadeIn() {
    if (continueCheck){
        // a new loop hasn't been called yet so proceed...

        $mySlide.fadeIn(fade, function() {
            timeout = setTimeout(slideFadeOut,display);
        }); 
    }       
};


function slideFadeOut() {
    if (continueCheck){
        // a new loop hasn't been called yet so proceed...

        slideNumber=slideNumber+1;

        $mySlide.fadeOut(fade, function() {
            //... code is here to check if I'm on the last slide and reset to #1...
            timeout = setTimeout(function(){startLoop(slideNumber)},100);
        });

     }   
};


startLoop(slideNumber);

Вышеуказанные удары по петле.

У меня есть элементы навигации, при нажатии которых я хочу остановить цикл выше, а затем перезапустить с новым начальным слайдом:

$(myNav).click(function(){
    clearTimeout(timeout);
    timeout = null;
    startLoop(thisItem);
})

Если я закомментирую 'startLoop ...' из события click, это действительно остановит начальный цикл. Однако, если я оставлю эту последнюю строку, это фактически не остановит начальный цикл. Зачем? То, что происходит, - то, что оба цикла, кажется, работают параллельно в течение периода.

Итак, когда я нажимаю на навигацию, вызывается clearTimeout, который очищает его.

1 Ответ

6 голосов
/ 29 апреля 2010

Что вам нужно сделать, это сохранить дескриптор, возвращенный setTimeout, и очистить его с помощью clearTimeout, чтобы прервать вращатель.

var timeout = null;

function doThatThing() {
    /* Do that thing. */

    // Schedule next call.
    timeout = setTimeout(doThatOtherThing, 5000);
}

function doThatOtherThing() {
    /* Do that other thing. */

    // Schedule next call.
    timeout = setTimeout(doThatThing, 5000);
}

function interruptThings() {
    if (timeout != null) {
        // Never mind, cancel the scheduled task.
        clearTimeout(timeout);
        timeout = null;
    }
}

При нажатии на элемент навигации просто наберите interruptThings(). Приятно то, что он вступит в силу немедленно, и вам не нужно делать какие-либо опросы или что-либо еще сложное.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...