Почему несколько вызовов setTimeout () вызывают так много задержек?

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

протестировано в Internet Explorer 9, анимация работает со скоростью в реальном времени (это должно занять 1,6 секунды, и это заняло ровно 1,6 секунды). Любой другой браузер будет ужасно отставать, с анимацией раз 4 секунд (Firefox 3 и 4, Chrome, Opera) и что-то вроде 20 секунд в IE 8 и под.

как IE9 может идти так быстро, в то время как все другие браузеры застряли в грязи?

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

EDIT: чтобы разработать в ответ на комментарии, вот план код:

link.onclick = function() {
    clearTimeout(colourFadeTimeout);
    colourFadeTimeout = setTimeout("colourFade(0);",25);

    clearTimeout(arrowScrollTimeout);
    arrowScrollTimeout = setTimeout("arrowScroll(0);",25);

    clearTimeout(pageFadeOutTimeout);
    pageFadeOutTimeout = setTimeout("pageFadeOut(0);",25);

    clearTimeout(pageFadeInTimeout);
    pageFadeInTimeout = setTimeout("pageFadeIn(0);",25);
}

каждая из четырех функций выполняет затухание на один кадр, затем устанавливает другой тайм-аут с увеличенным аргументом до конца анимации.

вы можете увидеть страницу в http://adamhaskell.net/cw/index.html (Имя пользователя: knockknock; пароль: goaway) (он имеет звук и музыку, которые могут быть отключены, но будьте осторожны!)- мой JavaScript очень грязный, так как я действительно не организовал его должным образом, но он прокомментирован немного так надеюсь вы можете видеть, в чем состоит общая идея.

2 ответов


несколько вещей:

  1. ваш тайм-аут составляет 25 мс. Это переводится в 40fps, который является очень высокой частотой кадров, чтобы попытаться достичь с помощью javascript. Особенно для вещей, связанных с манипуляцией DOM,которые могут вызвать переливы. Увеличить его до 50 или 60. 15fps должно быть более чем достаточно жидкости для видов анимации, которые вы делаете. Вы не пытаетесь отображать видео здесь, просто перемещаете вещи по странице.

  2. Не используйте строки в качестве первых параметр setTimeout(). Особенно если вы заботитесь о производительности. Это заставит javascript перекомпилировать строку каждого кадра анимации. Вместо этого используйте функцию. Если вам нужно передать аргумент, используйте анонимную функцию, чтобы обернуть функцию, которую вы хотите выполнить:

    setTimeout(function(){
        pageFadeIn(0)
    },50);
    

    это будет компилироваться только один раз при загрузке скрипта.

  3. как упоминал Бен, дешевле использовать один setTimeout для планирования функций. Если на то пошло, код ясность может улучшиться с помощью setInterval вместо этого (или это не может, зависит от вашего стиля кодирования).


дополнительный ответ:

Программирование анимации javascript - это оптимизация и компромисс. Можно оживить много вещей на странице с небольшим замедлением, но вам нужно знать, как это сделать правильно и решить, чем пожертвовать. В качестве примера того, сколько можно анимировать сразу, - это демо-стратегия в реальном времени игру я написал пару лет назад.

среди вещей, которые я сделал для оптимизации игры:

  1. Ходячие солдаты состоят только из двух кадров анимации, и я просто переключаюсь между двумя изображениями. Но эффект тем не менее очень убедительно. Вам не нужна идеальная анимация, только та, которая выглядит убедительно.

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


Ну, это много javascript (несмотря на "четырехкратную дозу удивительности":)

вы запускаете много последовательности setTimeout, я не уверен, насколько хорошо JS-двигатели оптимизированы для этого.. в частности, в IE

хорошо, может быть, просто грубое предложение... Вы могли бы написать небольшой двигатель ГРМ.

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

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

вы глобальное событие будет выглядеть следующим образом:

var events = {

        fade1 : {
            fn : func_name,
            delay : 25,
            params : {}
        }

        fadeArrow : {
            fn : func_name,
            delay : 500,
            params : {}
        }

        slideArrow : {
            fn : func_name,
            delay : 500,
            params : {
                arrow:some_value
            }
        }

    }

затем создайте функцию для цикла через них с интервалом (возможно, 10 или 20 мс) и уменьшите задержки, пока они не завершатся, и запустите функцию с параметрами в качестве параметра функции (функция проверки.call for that).

Как только вниз, огонь setTimeout снова с той же задержкой..

чтобы отменить событие просто удалить свойство из списка событий..

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

это уменьшило бы все до одного обработчика таймаута..

(просто идея)