Mots-clefs
Les éléments de base du JS
doivent vous êtes familiers; parmi eux:
let const for…of… => … async function* class
Events
Là encore, il existe énormément d'évènements en javascript et
le MDN vous en donne la liste exhaustive
, dont les plus intéressants/exotiques sont peut-être:
ClipboardEvent CustomEvent DeviceLightEvent DevicemotionEventKeyboardEvent MouseEvent MessageEvent NavigatorOnLine PageTransitionEvent PointerEventDeviceProximityEvent UserProximityEvent WheelEvent
.
Tâchez de bien comprendre chacun de ceux que vous utilisez:
input
et
change
n'ont pas la même signification!
Notez aussi qu'il existe plusieurs fonctions utiles liées à ces events,
comme
preventDefault() stopPropagation()
, lié à l'interface Event
elle-même
et
dispatchEvent
, liée à l'interface EventTarget
(souvent, un noeud du DOM, mais pas uniquement).
L'Event "click" peut être triggé par un terminal tactile (touch), vocal, ou autre: ce n'est pas forcément un click souris, malgré son nom.
Il n'y a pas de moyen standard de connaître "l'élément d'origine de l'Event". Ce genre de besoin reflète d'ailleurs un mauvais usage des events: posez le listener sur l'objet "d'origine" que vous souhaitiez écouter, tout simplement!
Form submit Event et formaction
Si un script ajoute un listener submit
sur un
<form>
et que ce formulaire a été soumis en utilisant
un <input|button formaction=…/>
,
alors le listener n'a aucun moyen standard de connaître la vraie destination
(action
) du formulaire. Mieux vaut alors faire plusieurs
form
, ou poser un listener
click
sur ces input|button
.
Promise
Une
Promise
est simplement un objet javascript, créé instantanément, et qui sera "résolu" plus tard, quand une opération
sera terminée. Quand cette "résolution" aura lieu, une callback sera appelée
C'est donc une forme "d'asynchrone", raison pour laquelle elle rejoint le concept de
async await
.
Cette interface est très utilisée par les APIs natives du VanillaJS. Tâchez de comprendre son principe de fonctionnement avant de plonger dans ces autres APIs.
Web APIs et interfaces
Il existe
un paquet d'APIs web et d'interfaces
entre la page HTML (le DOM) et le code javascript.
Je vous recommande donc d'en faire le tour, et de surtout maîtriser celle que vous utiliserez.
Les plus utiles et remarquables sont sans doute:
ChildNode CharacterData DOMClassList / DOMTokenList DOMException DOMPoint
L'article du MDN sur le DOM liste aussi de nombreuses autres interfaces utiles.
API/interfaces notables
Voici quelques APIs (en vrac) dignes d'intérêt dans le cadre d'un jeu web.
Atomics
: type de données pour le multi-thread
Audio API
: génération et manipulation de sons en temps réel
ArrayBufferView
/
Blob
/
File
: créer/manipuler/sauver des fichiers/flux binaires
Il n'est pas possible d'accéder directement aux fichiers sur le système du client (PC/mobile): il faut que l'utilisateur le sélectionne dans un input file, ou qu'il l'enregistre manuellement.
BroadcastChannel
: communication "one-to-many" entre browsing contexts (iframes, onglets, fenêtres, etc);
cf window.postMessage
pour le "one-to-one"
Cache API
: gérer vous-même le cache du navigateur
Cette API est à éviter: tout est déjà présent dans le cache HTTP en général , vous n'avez plus qu'à apprendre à l'utiliser.
Canvas API
: dessiner quelque chose en 2D ou 3D
Ne vous jetez pas dessus pour faire votre jeu web: canvas ne sert qu'au dessin arbitraire, pas pour créer une interface, des boutons, etc.
Crypto API
: fonctions de hashage, cryprographie, etc. Vous n'en aurez probablement pas besoin.
Si vous avez besoin de cette API, alors assurez-vous d'abord de ne pas réinventer (mal!) des systèmes de sécurité déjà existants (et qui, eux, sont bien conçus et implémentés)
CSS Object Model (CSSOM)
: manipulations du CSS via javascript
Attention à ne pas la sur-utiliser: le JS ne doit pas servir à faire du rendu CSS!
Document
: une API vaste,
dont document.querySelector
remplace l'ancien
$()
de jQuery pour sélectionner un élément
scrollIntoView
: fait défiler la vue jusqu'à rendre l'élément ciblé visible (avec des options: en haut, au centre,
défilement doux, etc)
DOMParser
: crée un arbre (document fragment) HTML à partir d'une string
(remplace $()
).
Fullscreen API
: passe une page/un élément en plein écran (cf
:fullscreen
)
Gamepad API
: accéder aux manettes éventuellement branchées à la machine
Si vous allez jusqu'à cette API, curiosité mise à part, privilégiez l'utilisation d'un SDK.
Géolocalisation
: accès aux donnees GPS du terminal
L'utilisateur peut refuser cette localisation: ne soyez pas intrusif sans raison valable dans le jeu!
Intersection Observer
: détecte quand un élément DOM est "visible à l'écran"
IndexedDB API
: stocke de grandes quantités de données dans le navigateur (des fichiers).
Ne la sur-utilisez pas, car elle n'est pas triviale à metttre en place, et elle a quand même une limite!
MediaQueryList
: détecter les changements de dimensions, ratio, orientation, etc du viewport (fenêtre).
Voir aussi l'API Screen.
Cette API sera souvent inutile car le CSS propose déjà des media queries.
MediaDevices API
: accès au micro et à la caméra (s'il y en a)
Mutation Observer
: exécute une callback à l'ajout/modification/suppression d'un noeud/attribut HTML.
Cette API est très utile dans un UserScript (plugin de navigateur).
Notification
: afficher des notifications (la forme dépend du support: PC, mobile, etc)
A moins d'être vraiment justifier, les notifications sont souvent refusées par les utilisateurs.
Server Side Events : réagir quand le serveur envoie des données au navigateur (un genre de "push").
Service Worker / Web Worker : exécuter des tâches de fond dans un "thread" séparé de la page web (calculs persistants), ou de gérer tout le trafic réseau du jeu (à éviter: ce n'est pas votre rôle)
Cette API est très délicate à utiliser: la mise à jour du Service Worker n'est pas triviale.
Speech API : reconnaissance/synthèse vocale
Un voice actor ("doubleur") donnera bien plus de vie à votre jeu web qu'un synthétiseur vocal.
Ne l'utilisez pas pour remplir, par la voix, des champs textes: c'est le rôle du navigateur de le faire!
URL : API permettant la manipulation d'urls.
Donc, n'utilisez plus jamais "a=b&c=d".indexOf("&")
!
Constraint Validation
: décrit précisément les conditions de validité d'un <input>
Privilégiez les attributs natifs avant de recourrir à cette API complexe.
Vibration API : fait vibrer le terminal, s'il en est capable (mobile, tablette, montre)
WebXR Device API (VR/AR) : accès aux données de réalité virtuelle ou de réalité augmentée (bonne chance!)
Web Assembly : faire (en gros) tourner du code C++ dans le navigateur.
Mon conseil? N'allez pas aussi loin!
Web Components : définir des tags et des attributs customs
Je pense, personnellement, que cette API n'est pas utile à un site web: le standard HTML
contient déjà tout ce qui vous est nécessaire comme tags/attributs HTML,
et les quelques besoin supplémentaires seront largement couverts par deux-trois fonctions JS
couplées à des document.querySelector(All)
.
WebRTC : communication directe entre eux deux navigateurs, sans passer par le serveur!
La gestion d'un tel réseau décentralisé est très complexe (donc, à éviter), et sera souvent impossible directement (réseaux NAT): vous aurez besoin d'un serveur intermédiaire dans la plupart des cas.
WebSocket : communication temps réelle et bi-directionnelles entre le navigateur et le serveur.
Si vous utilisez PHP, cette API sera trop complexe à mettre en place: laissez tomber, ou changez de techno côté serveur.
XPath
Il est possible d'utiliser des expressions XPath en Javascript, pour sélectionner des éléments de la page.
Face aux sélecteurs CSS, les sélecteurs XPath ont l'avantage de proposer des axes descendants:
vous pourrez sélectionner tous les paragraphes qui contiennent un passage en gras par exemple. Voyez
la doc du MDN sur XPath
et
la sélection d'un élément d'un page via XPath
via document.createExpression
pour plus d'informations.
Accessibilité
Tout ce qui est bricolé en Javascript n'est pas facilement accessible.
Les jeux à base de canvas
seront très difficiles à porter
sur d'autres supports (mobile, tablette, PC, lecteur d'écran ou commande vocale) et risquent
d'amener énormément de maintenance (présente et à venir).
AJAX n'est pas indispensable
Polymer encore moins…
Ne recodez pas un navigateur dans votre site web via Javascript.
Usez des iframe
si besoin, et assurez-vous idéalement
que votre jeu reste utilisable même si vous dégagez votre Javascript.
Vous réduirez ainsi considérablement votre charge de travail et de maintenance.
XMLHttpRequest
Dans les cas où AJAX vous serait nécessaire, oubliez jQuery et servez-vous directement de
XMLHttpRequest
(l'objet natif pour AJAX).
Vous pourrez comprendre et piloter intégralement vos requêtes client/serveur, headers HTTP
inclus (entre autres). Jetez aussi un oeil sur les autres API comme
fetch()
et
sendBeacon
Il est possible de faire des pages dynamiques sans AJAX! Voir la démo d'un formulaire (+popin) sans AJAX
Non, utiliser un framework JS ne règle pas le problème de la maintenance: vous allez au contraire devoir gérer les soucis de navigateur (compatibilité), et les soucis du framework (montées de version).
FormData
L'API FormData peut se coupler à XMLHttpRequest pour permettre à l'utilisateur d'entrer des informations (via un formulaire classique), puis de récupérer ces informations dans votre code JS, et de les transférer au serveur via XMLHttpRequest. Vous aurez alors la possibilité de traiter la réponse du serveur dans votre code JS.
Ajouter un BOM
Pour certains fichiers UTF-8, il peut être nécessaire d'ajouter un BOM lorsqu'un javascript génère le contenu
du fichier (histoire que ce dernier soit bien lu comme du UTF-8). Pour cela, préfixez simplement les données
du Blob par \uFEFF, qui est
le caractère UTF-8 générant le BOM binaire 0xEF 0xBB 0xBF
.
Si le BOM est plus exotique, vous pouvez passer par un Uint8Array
.
Optimiser Javascript
- Evitez les frameworks lourds (dont jQuery): ECMA6 propose nativement la quasi totalité de ce que ces framework émulaient (et ce qui n'est pas proposé est souvent une mauvaise pratique, à éviter donc)
- Limitez les manipulations du DOM: créez un noeud, stockez-le dans une variable JS sans l'ajouter au DOM, ajoutez à ce parent tous les enfants dont il a besoin, et insérez-le en dernier lieu dans le document
-
Simplifiez les boucles via
for (var i=0, s=array.length; i<s; i--)
pour ne pas recalculerarray.length
à chaque itération (ou utilisezfor … of …
oufor … in …
) -
Cachez les objets globaux:
var w = window
puis utilisezw
dans les boucles au lieu dewindow
, qui doit sinon être résolu à chaque itération - Ordonnez correctement les tests: ceux qui risquent le plus d'échouer en premier
- N'utilisez pas le mot-clef
with
-
Limitez les
try { … } catch (…) { … }
: ne vous en servez pas comme d'unreturn
! - Appliquez strictement le standard actuel (ECMA-262 6e édition en 2016)
- Servez-vous du profiler du navigateur pour savoir quelles parties du code sont vraiment lentes
- Préoccupez-vous de l'optimisation que si nécessaire: n'anticipez pas inutilement les problèmes de performances, et ne les réglez que s'ils sont vraiment humainement perceptibles
- La limite mémoire de Javascript est similaire à celle du programme (navigateur) qui l'exécute, donc éviter de charger des ressources (vidéos, sons, images) dans la mémoire JS!