#javascript #firefox #google-chrome #lag
#javascript #firefox #google-chrome #задержка
Вопрос:
У меня есть сложная последовательность анимации, включающая затухания и переходы в 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 очень неаккуратен, поскольку я на самом деле не организовал его должным образом, но он немного прокомментирован, так что, надеюсь, вы сможете увидеть, в чем заключается общая идея.
Комментарии:
1. Не могли бы вы пояснить? Сама анимация выполняется медленно или существует время ожидания между различными частями анимации из-за ожидания истечения тайм-аута? Также помог бы некоторый код.
2. Четыре части анимации: (1) Исчезновение текущей страницы с помощью
opacity
, (2) Исчезновение на новой странице с помощьюopacity
, (3) Исчезновение цвета страницы с помощьюbackground-color
, (4) Указатель прокрутки на панели навигации с помощьюleft
(Да, это очень излишне, но это в основном для показухи). Анимация должна выполняться со скоростью 40 кадров в секунду (интервал ожидания составляет 25 мс), но в более медленных браузерах каждый кадр занимает как минимум в два раза больше времени, и видны скачки.3. Публикация кода может быть для вас проблемой, потому что сейчас он такой грязный…
4. вероятно, вы где-то упускаете танцующего ребенка
5. Я думаю, что происходит слишком много всего одновременно, это не имеет ничего общего с
setTimeout
. Возможно, вы захотите использовать эту страницу для продвижения улучшенного движка Javascript в IE9, но если вы заинтересованы в том, чтобы другие браузеры могли с этим справиться, вам, возможно, придется немного смягчить эффекты. (Или сделайте их лучшим способом. На самом деле я не собираюсь просматривать ваш беспорядочный скрипт для оптимизации. :))
Ответ №1:
Несколько вещей:
-
Ваш тайм-аут составляет 25 мс. Это приводит к 40 кадрам в секунду, что является очень высокой частотой кадров, которую можно попытаться достичь с помощью javascript. Особенно для вещей, связанных с манипуляциями с DOM, которые могут вызвать перепрошивки. Увеличьте его до 50 или 60. 15 кадров в секунду должно быть более чем достаточно для тех видов анимации, которые вы делаете. Вы не пытаетесь отображать здесь видео, просто перемещаете объекты по странице.
-
Не используйте strings в качестве первого параметра для
setTimeout()
. Особенно если вы заботитесь о производительности. Это заставит javascript перекомпилировать строку в каждом кадре анимации. Вместо этого используйте функцию. Если вам нужно передать аргумент, используйте анонимную функцию для переноса функции, которую вы хотите выполнить:setTimeout(function(){ pageFadeIn(0) },50);
это будет скомпилировано только один раз при загрузке скрипта.
-
Как упоминал Бен, дешевле использовать один setTimeout для планирования функций. Если уж на то пошло, ясность кода может улучшиться, если вместо этого использовать setInterval (а может и нет, зависит от вашего стиля кодирования).
Дополнительный ответ:
Программирование анимации на javascript — это оптимизация и компромисс. На странице можно анимировать множество объектов с небольшим замедлением, но вам нужно знать, как это сделать правильно, и решить, чем пожертвовать. В качестве примера того, как много можно анимировать одновременно, можно привести демо-версию стратегической игры в реальном времени, которую я написал пару лет назад.
Среди вещей, которые я сделал для оптимизации игры, следующие:
-
Шагающие солдаты состоят всего из двух кадров анимации, и я просто переключаюсь между двумя изображениями. Но, тем не менее, эффект очень убедительный. Вам не нужна идеальная анимация, достаточно той, которая выглядит убедительно.
-
Я использую один setInterval для всего. Это дешевле с точки зрения процессора и проще в управлении. Просто определите базовую частоту кадров, а затем запланируйте запуск разных анимаций в разное время.
Комментарии:
1. Еще раз спасибо за ответ. Я не знал, что вы можете передать функцию setTimeout — в будущем это намного упростит задачу! Я обязательно дам вам знать, если это сработает. Я также вдвое уменьшу частоту кадров (я позаботился о том, чтобы во всех анимациях было количество кадров в степени два, поскольку это позволяет легко масштабировать и поддерживать идеальную точность чисел, если я не ошибаюсь)
2. Хорошо, все работает нормально. Firefox по-прежнему работает медленнее, но я думаю, что в IE9 лучше просто сам движок, потому что медлительность далеко не так плоха, как была (теперь это занимает едва ли на полсекунды больше, чем следовало бы). Большое вам спасибо за помощь — я не знал, что вы можете передать функцию setTimeout.
3. это очень хороший ответ (и пример)
4. @slebetman Ссылка на ваш ответ больше недоступна. Не могли бы вы перепостить свой исходный код, если он у вас все еще есть?
5. @UpTheCreek: 40 кадров в секунду были очень высокой частотой кадров в 2010 году — это замедлило бы IE6 до обхода. Да, в 2010 году нам все еще приходилось поддерживать IE6 и IE7
Ответ №2:
Что ж, это многовато для javascript (несмотря на «четырехкратную дозу удивительности» 🙂
Вы запускаете много последовательностей setTimeout, я не уверен, насколько хорошо движки JS оптимизированы для этого .. особенно IE <= 8
Хорошо, может быть, просто приблизительное предложение… Возможно, вы могли бы написать небольшой механизм синхронизации.
Поддерживайте глобальный объект, который хранит ваши текущие запущенные временные события с функцией для запуска и задержкой…
Затем создайте один обработчик setTimeout, который проверяет соответствие этому глобальному объекту и уменьшает задержку на каждой итерации, и вызывайте функцию, когда задержка становится < 0
ваше глобальное событие выглядело бы примерно так:
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 снова с той же задержкой..
Чтобы отменить событие, просто отключите свойство из списка событий..
Создайте несколько методов для добавления / удаления событий в очереди, обновления параметров и так далее..
Это сократило бы все до одного обработчика тайм-аута..
(просто идея)
Комментарии:
1. Я попробую это завтра (поскольку сейчас здесь 3 часа ночи) и дам вам знать, как это получается.