Проблемы с производительностью HTML5 Canvas в некоторых мобильных браузерах.

Привет, у меня есть веб-приложение, которое должно работать как в браузерах смартфонов, так и в настольных браузерах. Хотя я ожидал получить любопытное поведение на небольших устройствах, таких как Iphone, я был вполне уверен, что он будет хорошо работать на Android Galaxy Tab, который является Android-устройством, с которым я могу проводить тесты в данный момент.

Теперь я установил несколько браузеров на Galaxy Tab, чтобы протестировать:

  • Родной браузер Android
  • Хром для Android
  • Фаерфокс для Android

На рабочем столе я использовал

  • Fire Fox
  • Гугл Хром

и, наконец, у меня есть Iphone для тестирования.

Веб-сайт использует холст HTML5 для рисования на основе пикселей и спрайтов, без причудливых преобразований, фильтров или эффектов, в основном простые пути и многоугольники. Я слушаю сенсорные события и использую requestAnimationFrame для правильной перерисовки.

В целом приложение хорошо работает в настольных браузерах, а также отлично работает в iOS Safari (iPhone) и Firefox на Android. Тем не менее, собственный браузер Android доставляет мне проблемы. Я настроил его так, что экран становится красным, когда javascript не отвечает, и почти всегда мигает при касании экрана.

Поэтому мне интересно, есть ли какие-либо известные проблемы с Android Native App и HTML5. Из-за несуществующего имени родного браузера довольно сложно найти информацию об этом в Google. Есть идеи, где я могу получить дополнительную информацию? Есть идеи, что может вызвать отставание родного браузера Android?

Есть несколько идей по этому вопросу:

  • iOS не поддерживает requestAnimationFrame, поэтому я заменил его заменой на основе тайм-аута. Если я использую эту замену в родном браузере Android, проблема сохраняется.

  • Я довольно регулярно использую AJAX (google clojure xhrio) для получения данных с сервера. Может ли быть так, что обратные вызовы для извлечения данных забивают мой конвейер событий?

  • Известно ли, что сообщения консоли журнала (console.log) замедляют работу приложений? Могут ли они вызвать повторный запуск браузера через дерево DOM или что-то связанное?


person wirrbel    schedule 24.04.2013    source источник
comment
Я не могу ответить на ваш реальный вопрос, но использование консоли может потреблять значительный объем памяти в зависимости от того, как вы ее используете. Особенно, если вы регистрируете большие объекты или ведете журнал очень часто.   -  person idbehold    schedule 24.04.2013


Ответы (2)


Я провел много экспериментов с холстом во многих браузерах. Некоторые проблемы с производительностью, которые я заметил:

Во-первых, о ваших предположениях:

  • Когда requestAnimationFrame поддерживается браузером, элементы рисования и само приложение более отзывчивы. Использование setTimeout или setInterval в качестве запасного варианта всегда возможно, но вам нужно быть осторожным с выбором времени. Этот надежный полифилл может немного помочь, но ничто по сравнению с родным requestAnimationFrame.

  • Если console.log вызывается каждый кадр (или почти), да, производительность падает. Поскольку собственный браузер Android не имеет объекта консоли, каждый раз, когда он вызывается, будет генерироваться ошибка, которая также способствует замедлению работы вашего приложения. Ты можешь это сделать:

    if(typeof console === "undefined"){ console = {}; }

  • Для ресурсоемких приложений реального времени веб-сокеты работают быстрее, чем HTTP-запросы. К сожалению, эта функция не поддерживается старыми родными браузерами Android. Если невозможно использовать веб-сокеты, следует свести к минимуму HTTP-запросы.

Примечание. Chrome для Android поддерживает большинство перечисленных здесь функций HTML5, включая requestAnimationFrame и websockets.

Больше информации:

  • Отрисовка текста с использованием контекста 2d fillText слишком накладно, но в некоторых браузерах это еще хуже. Предварительно визуализируйте свои тексты на другом холсте или используйте растровые шрифты. (В родном браузере Android, после замены filltext отрисовки на пре-рендеринг, производительность выросла с 10-15 FPS до 30-45 FPS в некоторых играх, которые я сделал).

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

  • Вам нужно свести к минимуму рисование в реальном времени. Предварительно визуализируйте свои материалы всякий раз, когда вы можете. Перерисовывайте только то, что изменилось и нуждается в обновлении.

  • Попробуйте написать эффективный с точки зрения памяти код, дружественный сборщику мусора.

Есть еще много вещей, которые нужно сделать. Я лишь привел несколько.

СОВЕТ: проведите несколько стресс-тестов для функций, в которых вы не уверены, снижают ли они производительность, и зафиксируйте результаты тестов.

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

Для получения дополнительной информации перейдите по ссылкам ниже:

Также ищите производительность в записях и руководствах.

РЕДАКТИРОВАНИЕ
Этот фрагмент кода jsfiddle показывает некоторые вещи, описанные в этом ответе, и дает примерный fps против эталона. Отредактируйте эту скрипку самостоятельно и проверьте ее.

person Gustavo Carvalho    schedule 25.04.2013
comment
действительно полезный и проницательный ответ. Очень ценю ;) - person wirrbel; 26.04.2013
comment
При использовании дополнительных холстов для предварительного рендеринга убедитесь, что их содержимое не обрезается, т.е. при повороте текста. в этом случае вы можете перевести содержимое на холст перед визуализацией, а затем переместить его обратно при использовании холста с помощью drawImage: preRenderCtx.translate(100, 100); preRenderCtx.rotate(rotation); preRenderCtx.fillText(char, 0, 0); context.drawImage(preRenderCanvas, x-100, y-100); - person Micha Schwab; 13.02.2018

В зависимости от того, что вы рисуете, наиболее распространенная стратегия повышения производительности с помощью холста Html5 заключается в использовании слоев (т. е. нескольких холстов) и обновлении только тех слоев, которые необходимо перерисовать, а не перерисовки всего объекта в каждом кадре анимации. Вы можете свернуть что-то подобное самостоятельно или использовать что-то вроде http://www.concretejs.com/. который представляет собой облегченную структуру холста Html5, которая позволяет выполнять периферийные функции, такие как обнаружение попаданий, наслоение, кэширование, поддержка соотношения пикселей, загрузки и т. д. Вы должны сделать что-то вроде этого:

var wrapper = new Concrete.Wrapper({
  width: 500,
  height: 300,
  container: el
});

var layer1 = new Concrete.Layer();
var layer2 = new Concrete.Layer();

wrapper.add(layer1).add(layer2);

// something happens which requires you to redraw layer2, but not layer1...
layer2.sceneCanvas.context.fillStyle = 'red';
layer2.sceneCanvas.context.fillRect(0, 0, 200, 100);
person Eric Rowell    schedule 02.04.2016