28 février 2021 · 2 min de lecture
Le Javascript est exécuté dans un seul processus (“single threaded” en anglais). Lorsqu’on démarre un long traitement, l’interface utilisateur peut être ralentie voire figée.
Pour pallier à ce problème les Web Workers sont apparus. Ils permettent d’exécuter un script en arrière plan, dans un autre processus.
Voici un exemple en pur Javascript.
Copiez le code suivant dans un document HTML test.html
. Ouvrez ce fichier dans le navigateur.
<span id="info">0</span>
<button onclick="start()">GO</button>
<script>
const start = () => {
console.log('started')
console.time('duree')
// simulation d'un long traitement
for (let i = 0; i <= 5000000; i++) {
// affichage du compteur
document.getElementById("info").textContent = i;
}
console.timeEnd('duree')
}
</script>
L’effet attendu quand on clique sur GO
est que l’affichage du compteur progresse durant la boucle. Or, cela ne se produit pas car le processus principal n’a pas la main pour modifier le rendu de la page web. Il n’est mis à jour qu’à la fin du traitement.
Créons un fichier worker.js
dans le même dossier que notre page test.html
:
self.onmessage = (e) => {
dojob(e.data.initialCount)
postMessage({ fini: true })
}
function dojob (initialCount) {
// simulation d'un long traitement
for (let i = initialCount; i <= 500000; i++) {
postMessage({ count: i })
}
}
A noter que le Web Worker n’a pas accès au DOM car il est exécuté en dehors de la page HTML principale. Ils peuvent communiquer via la transmission de messages. Chaque partie peut envoyer des messages à l’aide de la méthode postMessage()
et réagir aux messages reçus grâce au gestionnaire d’évènement onmessage
.
Modifions le fichier test.html
:
<span id="info">0</span>
<button onclick="start()">GO</button>
<script>
let worker = new Worker('worker.js')
let count = 0
// lorsque le worker enverra un message
worker.onmessage = (e) => {
// l'instruction de terminer est reçue
if ('fini' in e.data && e.data.fini) {
console.log('the end')
worker.terminate()
return
}
// on met à jour l'affichage du compteur
document.getElementById("info").textContent = e.data.count;
}
function start () {
// démarrage du worker
worker.postMessage({ initialCount: count });
}
</script>
Par sécurité les navigateurs n’autorisent pas l’inclusion d’un fichier javascript depuis le système de fichiers. Le code Worker('worker.js')
renverra une erreur. Pour la démonstration, il est donc nécessaire d’utiliser un simple serveur web. Vous avez le choix selon votre language préféré :
En Python :
python3 -m http.server
NodeJS :
npm install -g http-server
http-server -p 8000
PHP:
php -S 127.0.0.1:8000
Allez à l’addresse http://0.0.0.0:8000/test.html
dans votre navigateur. Cliquez sur GO
. Vous constatez maintenant que le compteur s’affiche en temps réel.