Javascript-форум (https://javascript.ru/forum/)
-   jQuery (https://javascript.ru/forum/jquery/)
-   -   Не предсказуемые тормоза в слайдере. (https://javascript.ru/forum/jquery/21916-ne-predskazuemye-tormoza-v-slajjdere.html)

Duda.Ml1986@gmail.com 29.09.2011 12:17

Не предсказуемые тормоза в слайдере.
 
Всем привет.
Возник такой вопрос:
Есть слайдер контента, как фон у дивов используются фото 1900 * 600 , при загрузке страницы слайды начинают автоматом прокручиваться, если находится на этой странице и глупо следить за их сменой все ок! А вот если перейти на другие вкладки, просто погулять (серфинг) нета, то вернувшись на страницу со слайдами они начинаю прыгать. В чем причина такого поведения?

Чтобы устранить это, ограничил количество прокруток слайдов, до 10.

Сам слайдер не привожу(код), много букаф. Вот ссылка на готовый вариант http://duvanov.net/slider.html

P.S. Иногда этого и не происходит!

DjDiablo 29.09.2011 13:14

Я плохо знаком с проблемой таймеров, анимацией пока не приходилось заниматься. Но всё же выскажу предположение. Насколько я знаю обработчики событий находятся в специальной очереди, общей для всех событий. Так как javascript язык однопоточный то и события обрабатываются строго по очереди. Если предположить что на закрытой вкладке обработчики только накапливаются а на открытой и накапливаются и исполняются, то при переходе от закрытой вкладки к открытой ты получишь исполнение всех накопленных обработчиков практически сразу,точнее без временных промежутков. Это будет выглядеть как ускоренная анимация. Либо если твои обработчики сами запускают jquery анимацию, ты получешь несколько анимаций сразу.

Как решение в голову приходят два варианта,

1й - задавать вызов следующего обработчик события, непосредственно в самом обработчике. В этом случае гарантированно небудут накапливаться обработчики. Если я правильно понимаю, делать это надо через setTimeout, ибо вызывается он однократно.
setTimeout(function(){
    /* полезный код... */
    setTimeout(arguments.callee, 20);//задаём следующий вызов обработчика в самом обработчике
  }, 20);


2й) В обработчике проверять время между вызовами обработчика(последним и текущим) и если оно меньше положенного, не исполняем полезный код.

ksa 29.09.2011 13:16

Цитата:

Сообщение от Duda.Ml1986@gmail.com
Вот ссылка на готовый вариант http://duvanov.net/slider.html

Для помощи в твоей проблеме (бесплатно) нужен не ссылка на "готовый вариант"... А простенький тестовый пример и тут.

Duda.Ml1986@gmail.com 29.09.2011 13:34

DjDiablo спасибо за исчерпывающий ответ. В действительности это так , накапливание черт его бери. Так что теперь все ок.

aphextwin 07.05.2012 16:53

Цитата:

Сообщение от DjDiablo
1й - задавать вызов следующего обработчик события, непосредственно в самом обработчике. В этом случае гарантированно небудут накапливаться обработчики. Если я правильно понимаю, делать это надо через setTimeout, ибо вызывается он однократно.

setTimeout(function(){
    /* полезный код... */
    setTimeout(arguments.callee, 20);//задаём следующий вызов обработчика в самом обработчике
  }, 20);

А вы не могли бы пояснить, в данной ситуации setTimeout переопределяется, или как? Не могу понять как прикрутить это к своему обработчику. Что такое arguments.callee тоже не совсем понятно. Я в js неопытен, не могли бы вы помочь найти решение проблемы?

DjDiablo 07.05.2012 19:32

aphextwin я не очень понял что вам конкретно непонятно.

f=function(){
     //полезный код
     setTimeout(f, 20);
}
f();//первый вызов.

алгоритм примерно такой
1) вы вызываете функцию f
2) начинается исполнение функции
2) в функции f есть функция setTimeout которой передаётся два параметра, 1 - это функция, 2 - это время по истечению которого нужно вызвать функцию в первом параметре
3) завершается исполнение функции.
4) проходит 20 мс, и теперь уже не вы а таймер вызывает функцию переданную в первом параметры, а дальше смотрите шаг два (только не повисните :) )


setTimeout вызывает указанную функцию только один раз по истечению указанного временного промежутка.

так как вызванной функции находится setTimeout, функция будет постоянно заставлять таймер вызывать саму себя

Всё что вам нужно для запуска это просто вызвать функцию f первый раз.

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

что касается arguments.callee, нужно же как то указать setTimeout какую функцию вызывать через 20мс.
думаю уместно говорить о трёх способах.
f=function c (){
   setTimeout(f,20);                          // первый способ
   setTimeout(c,20);                         // второй способ
   setTimeout(arguments.callee,20);    // третий способ
}

aphextwin 08.05.2012 14:40

Сегодня переписал все по вашему совету, но нужного эффекта не достиг )

Код такой:

$(window).load(function(){
    autoAdvance();
});

function autoAdvance()
{
    $('#left').trigger('click',[true]);
    // тут я пробовал вставлять исполняемый код, роли не играет. Все равно очередь накапливается...
    setTimeout(autoAdvance,3000);
}


События все равно накапливаются, слайдер, при переключении табов так же пляшет. Может вы поймете что я не так делаю?

Рабочая проблема тут : test.digis.kz

DjDiablo 08.05.2012 23:18

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

А вот ручное переключение между слайдеми у вас сударь работает как то через попу. Только накопление событий тут не причём.
Решить это можно так.
в случае нажатия, унечтожается старый таймер.
и создаётся новый, вызывающий autoAdvance через 20 секунд к примеру.

то есть мы попросту даём пользователю время рассмотреть тот слайд, на который он сам переключился.
А у вас сейчас получается что пользователь меняет слайд, и следом срабатывает таймер который меняет слайд обратно ))

Ещё один интересный момент, это смена кадра в момент переключения на вкладку.
Это происходит потому что обработчик ждёт возможности быть выполненным, и выполняется при первой возможности.
Это конечно и не баг, и можно оставить так. Но можно изменить модель поведения. К примеру замерять временной интервал между двумя вызовами обработчика, и если интервал окажется больше критического значения, то не вызывать trigger.
Когда пользователь вернется на вкладку он будет видеть три секунды тот слайд, который был на экране в момент когда пользователь уходил. То есть переключение слайда произойдет через три секунды, а не сразу после возвращения.
Однако я сомневаюсь что пользователи вообще заметят этот выпендреж. :)

aphextwin 10.05.2012 13:01

Возможно вы меня не правильно поняли.
Когда я открываю сайт - слайдер работает, меняет картинки. Правда, при ручном переходе между слайдерами и вправду стоит убивать таймер, спасибо за идею! Но стоит уйти на другую вкладку на пару минут и вернуться - как я думаю, события накапливаются, и слайдер начинает бешено листаться. Надо заметить, что это наблюдается в фф 701, хром 18.
В опере вроде все работает как надо.

Расскажу о принципе работы, верстку не трогаю, только скрипт:

Вот так происходит смена слайдов, все в принципе просто, конечно используем jq:
$('#left').click(
        function()
        {
            curr = $('.slider_container').find('.slider_item:visible');
            curr.fadeOut();
            if(curr.next().length)curr.next().fadeIn();
            else $('.slider_container').find('.slider_item:first').fadeIn();
        }
    );


Далее, первый вызов ф-ции происходит по событию document.ready т.е. при загрузке страницы.

А сама ф-ия autoAdvance() либо делает вид, что кликает по стрелочке
$('#left').trigger('click',[true]);

либо исполняет тот же код:
curr = $('.slider_container').find('.slider_item:visible');
curr.fadeOut();
if(curr.next().length)curr.next().fadeIn();
else $('.slider_container').find('.slider_item:first').fadeIn();

потом происходит вызов самой себя, через задержку в 7 секунд:
timeOut = setTimeout(autoAdvance,7000);

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

Я тоже хотел сделать проверку временного интервала, но чего то не нашел аналога php time() в js. Может вы подскажете, как это сделать.

vadim5june 10.05.2012 13:16

почитайте вот здесь
http://habrahabr.ru/post/114358/


Часовой пояс GMT +3, время: 20:28.