Pull to refresh

Repaint для больших картинок

Reading time 3 min
Views 2K
Repaint происходит средствами процессора, браузер тратит на это определенное время. При анимации это время негативно влияет на производительность. Я уперся в эту проблему, когда мне надо было анимировать листалку из картинок большого разрешения весом 100-200kB. Причем в ряде браузеров проблема выглядела совсем катастрофически.

Эта статья не претендует на строгость изложения и на окончательные выводы. Однако хотелось поделиться находкой с сообществом. Основной вывод такой: операции с картинками надо реализовывать средствами [canvas], которая нагружает видеокарту, не надо использовать обычные теги [img], которые служат простой презентации графики.

Итак, теперь по порядку.

Имеется следующая задача: сменить одну картинку, у которой масштаб меньше 100%, на другую — с аналогичным масштабом.

Мы говорим: «Нет ничего проще! Меняем атрибут src у тега img.» Так вот, если посмотреть, как это происходит с помощью Timeline в Webkit-based браузере, то увидим, что генерируется событие repaint и для больших картинок ротация занимает приличное время.

Попробуем менять фоновую картинку, в таком случае. Масштаб можно задавать CSS3 свойством backgroung-size. Немного быстрее.

Если использовать проприетарный zoom, ситуация тоже не сильно улучшается.

Попробуем рисовать картинки на канве — все радикальным образом изменится! Repaint занимает 0ms.

В качестве наивной иллюстрации к тому, что сказано выше, может быть следующий код (использование jquery неоправданно, но для примера это не важно):

<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
</head>
<body>
<div style="display:none">
<img id="im1" src="img2.jpg"/>
<img id="im2" src="img3.jpg">
</div>
<div><span>IMG SRC</span>
<div><img class="rotor" src="img2.jpg" style="border:1px solid #000;" alt="" width="400" height="200"/></div>
</div>
<div><span>BACKGROUND</span>
<div class="rotor" style="border:1px solid #000; width: 400px; height: 200px; background: url(img2.jpg) no-repeat; background-size: 400px 200px;"> </div>
</div>
<div><span>CANVAS</span>
<div>
<canvas id="canvas" class="rotor" width="400" height="200" style="border:1px solid #000;"></canvas>
</div>
</div>
<script>
var ctx = document.getElementById('canvas').getContext('2d')
   var img = document.getElementById('im1')
   img.onload = function(){
     ctx.drawImage(img,0,0,400,200)
   }
   $('.rotor').click( function(){
   if( $(this).is('img') ) {
   $(this).attr('src', 'img3.jpg')
   }
   if( $(this).is('div') ) {
   $(this).css('backgroundImage','url(img3.jpg)')
   }
   if( $(this).is('canvas') ) {
   var img = document.getElementById('im2')
       ctx.drawImage(img,0,0,400,200)
   }  
   $(this).css('borderColor','red')
   })
</script>
</body>
</html>


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

image

Данные слишком сильно разнятся, так что их сравнивать можно только в рамках одного браузера, причем сравнивать именно порядок; я сомневаюсь, что они показывают объективное время выполнения. Для webkit-браузеров значения взяты из встроенного отладчика (вкладка timeline). Firefox 7 был оценен через dynaTrace (к сожалению, этим же инструментом не удалось измерить IE9).

dynaTrace вообще выдал достаточно противоречивые результаты: поле duration, определяющее время исполнения в асинхронном режиме, было рекордным 424.54ms для “чистого” времени исполнения 3.98ms.

image

Измерение с помощью Speed Tracer (Google) тоже преподнесло сюрприз: значения представились в виде 250, 84, 84. В общем, в некотором смысле, возникает больше вопросов, чем ответов.

image

Однако, я проверил эти примерные выкладки практикой: замена тега img на canvas принесло ускорение на порядок в Chrome и лучшую производительность в Opera (которая вообще выпала из рамок исследования скорости repaint). Firefox стал при этом более стабильным. Я объяснил все это переносом вычислений с процессора на видеокарту.

Надеюсь, мне удалось убедить не использовать [img] не по назначению. С другой стороны, возникло много вопросов и недоумений по поводу измерения скорости перерисовки в браузерах. Надеюсь на комментарии, я специально привел скриншоты с измерениями. Критика методологии приветствуется!
Tags:
Hubs:
+27
Comments 11
Comments Comments 11

Articles