Javascript asynchrone
Les navigateurs modernes prennent en charge 2 nouveaux attributs pour la balise HTML <script>
: async et defer.
Ces attributs modifient la manière dont le navigateur procède pour charger la page web, nous allons voir comment.
Avant de commencer à expliquer le rôle de ces 2 attributs, il est nécessaire de comprendre ce qui se passe en temps normal, lorsqu'un navigateur charge une page web incluant des scripts Javascript :
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>JS Bin</title> <script src="http://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.6.2/html5shiv.js"></script> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <script src="http://cdnjs.cloudflare.com/ajax/libs/less.js/1.3.3/less.min.js"></script> <script src="mon-script.js"></script> </head> <body> </body> </html>
Lorsque le navigateur va afficher cette page web, il va inclure les scripts un par un, et les télécharger puis les exécuter entièrement et séquentiellement (dans l'ordre dans lequel ils sont inclus dans le code HTML).
Dans certains cas, ce mode de fonctionnement est problématique, car il peut potentiellement ralentir le chargement de la page, voir même bloquer son affichage (empêchant la survenue de l'événement document ready ou window load).
Tous les scripts ne sont pas forcément nécessaires sur une page web, je pense notamment aux scripts tiers (qui viennent d'autres sites web) comme :
- Les outils web analytics (Google Analytics, Xiti...)
- Les scripts de régie publicitaire (Google Adsense, SmartAdserver, BuySellAds...)
- Les "widget" style Youtube, Twitter ou Facebook
Et bien c'est pour résoudre ce problème que les attributs async et defer ont été implémentés.
Attribut <script> async
L'attribut async se place dans la balise <script>
, comme ceci :
<script async src="mon-script.js"></script>
L'effet de cet attribut est simple : le navigateur ne va pas être bloqué par ce script, il va continuer son analyse de la page web tout en téléchargeant le javascript inclus en parallèle. Une fois que le téléchargement du script sera terminé, le code Javascript qu'il contient va être exécuté normalement, comme n'importe quel code JS.
De cette manière, si pour une raison ou pour une autre le téléchargement du script ne fonctionne pas ou est ralenti (serveur web surchargé, serveur down, serveur en maintenance...), cela ne va pas ralentir le chargement de la page (par contre le javascript qui devait être inclus ne sera pas exécuté).
Google Analytics utilise cette technique pour son code de tracking asynchrone.
L'attribut async est compatible avec tous les navigateurs modernes :
- Firefox 3.6+
- Chrome 2+
- Safari 5+
- iOS 5+
- Android 3+
- Internet Explorer 10
La page du jour est collage spécial avec excel, bonne lecture.
Opera ne supporte pas encore cette fonction.
Attribut <script> defer
Le fonctionnement de defer est assez proche de async : le téléchargement du script se fait en parallèle (non bloquante). Par contre le javascript est exécuté après le chargement de la page (quand le parseur HTML a terminé l'analyse et la construction du DOM), alors qu'avec async il est exécuté dès que le téléchargement est terminé.
defer est moins bien supporté que async, c'est pour ça que je vous déconseille son utilisation. Si vous voulez imiter le fonctionnement de defer, il suffit d'utiliser async en déclarant un handler à l'événement DOM ready dans le script, ce qui revient au même, puisque le code sera alors exécuté après le chargement du DOM.
Méthodes alternatives
Il est possible d'imiter le fonctionnement de async sur les navigateurs qui ne supportent pas cette fonction, pour cela il existe de nombreuses méthodes et surtout de nombreuses implémentations.
La plus utilisée est le "script loading pattern", qui consiste à charger un script via un autre script, qui se charge en fait de créer un élément <script> dynamiquement plutôt que de le placer dans le code HTML. C'est cette technique qui est utilisée par Google Analytics :
(function(){ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); })();
Découvrez ce tutoriel photoshop : botte magique à lire tout de suite !
Tu dis defer est moins bien supporté que async, il me semble que c'est le contraire :
http://caniuse.com/#feat=script-defer
http://caniuse.com/#feat=script-async