Voorheen werd Flash vaak gebruikt om online spelletjes en andere multimediale toepassingen te bouwen. Met de komst van het HTML 5 canvas is deze plug-in steeds minder vaak nodig. Dergelijke toepassingen gebruiken vaak veel afbeeldingen die gedownload moeten worden naar de browser. Dit kan lang duren, maar er zijn mogelijkheden om dit te verbeteren.

Het probleem
Volgens de specificatie van het http protocol zou een browser slechts 2 requests naar een server simultaan mogen afvuren. Gelukkig houden alle moderne browsers zich hier niet aan en ligt het aantal requests hoger. De meeste browsers houden het op 6 a 8 simultane requests (IE 11 iets meer). Dit betekent dat wanneer er meer dan 6 a 8 items van de server moeten komen, er gewacht moet worden tot een ander request afgerond is, alvorens een nieuwe request uitgevoerd kan worden.
Dus wanneer je een pagina (eerste request) hebt, met 3 style sheets, 2 jQuery referenties, 4 javascripts en 20 afbeeldingen, er in totaal 30 requests afgevuurd moeten worden. Met maar 6 a 8 requests simultaan, wordt er dus best veel gewacht.
De oplossing
Wellicht heb je ooit gehoord (of gebruik gemaakt) van CSS Sprites. Het idee is dat je meerdere afbeeldingen samenvoegt tot 1 afbeelding en dus 1 request. Deze kun je vervolgens met CSS background-position op een div tonen zodat je alleen dat stukje van de grote afbeelding te zien krijgt dat je daadwerkelijk wilt zien.
Dit zelfde principe is prima te gebruiken voor het HTML5 Canvas. De methode context.drawImage() staat toe dat je de X en Y positie en de hoogte en breedte opgeeft van het stukje dat je van een image wil tekenen op het canvas.
context.drawImage(
image,
sourceX,
sourceY,
sourceWidth,
sourceHeight,
destinationX,
destinationY,
destinationWidth,
destinationHeight
)
Dat kunnen we dus gebruiken om 1 grote afbeelding aan te leveren met daarop alle afbeeldingen die we nodig hebben en dan op het canvas de verschillende stukjes tekenen alsof het losse afbeeldingen zijn.
Voorbeeld
Om het effect te demonstreren heb ik een (versimpeld) voorbeeld gemaakt. 100 afbeeldingen moeten getoond worden op een canvas.
In de afbeelding hieronder (een weergave van de F12 tools) kun je goed zien wat er gebeurt. Bij pijl 1 wordt het HTML document gedownload. Hierin staan dan requests voor de afbeeldingen. Bij blok 2 zie je dat deze simultaan gebeuren, maar dat er daarna gewacht moet worden (Rood). Verder naar beneden zie je dat dit uiteindelijk behoorlijk op kan lopen.
Resultaat: Downloaden + tekenen op canvas -> 531 milliseconde
Wanneer alle 100 afbeeldingen worden samengevoegd wordt het bestand natuurlijk groter, maar is er, naast de pagina zelf, maar 1 request nodig. De code zal iets aangepast moeten worden voor het "uitknippen” van de benodigde kleine afbeeldingen, maar de performance is wel beter.
Resultaat: Downloaden + tekenen op canvas -> 330 milliseconde
Iets er tussen in kan natuurlijk ook! Stel, je verdeelt de 100 assets over 10 afbeeldingen. Dan kunnen er meerdere requests simultaan lopen (wat sneller is dan 1 groot request), maar niet zo veel dat er lang gewacht moet worden op andere requests.
Resultaat: Downloaden + tekenen op canvas -> 161 milliseconde
De balkjes worden altijd beeldvullend weergegeven, dus op het eerste gezicht lijkt het niet veel korter, maar als je de getallen bekijkt, zijn we van 531ms terug naar 161ms. Dat is toch een groot verschil. Nu heb ik deze test lokaal uitgevoerd. Remote zal dit effect alleen maar toenemen.
Conclusie
De tijd die het kost om de plaatjes d.m.v. het canvas ‘in stukken te knippen’ is vele malen minder dan de tijd die het kost om veel verschillende assets van een server te downloaden. Ik weet niet of er al een officiele naam voor is, maar laten we het voorlopig CSS Sprites voor Canvas noemen ;-)