Почему множественные вызовы setTimeout () вызывают такое большое отставание? - PullRequest
6 голосов
/ 18 ноября 2010

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

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

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

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

РЕДАКТИРОВАТЬ: Чтобы уточнить в ответ на комментарии, вот схема кода:

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 ]

12 голосов
/ 18 ноября 2010

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

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

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

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

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

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


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

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

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

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

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

3 голосов
/ 18 ноября 2010

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

Вы запускаете много последовательности setTimeout, я не уверен, насколько хорошо оптимизированы движки JS для этого .. особенно IE <= 8 </p>

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

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

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

Ваше глобальное событие выглядит примерно так:

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 мс) и уменьшать ваши задержки, пока они не завершат работу, и не запустят функцию с параметрами в качестве параметра функции (проверьте для этого Function.call).

Вниз, снова включите setTimeout с той же задержкой.

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

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

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

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

...