Articles

JavaScript Web Workers:Un débutant'Guide

En 2019, l’écosystème web a évolué au point où le navigateur est un environnement d’exécution pour les applications construites sur JavaScript. Cela se reflète dans la rapidité avec laquelle l’industrie propose de nouveaux frameworks, paradigmes, chargeurs et bundlers de modules, gestionnaires de dépendances, outils de construction et gestionnaires de paquets année après année.

Lorsque JavaScript a été conçu au début d’Internet, la direction du développement d’Internet n’était pas claire. En raison du changement constant et rapide de l’industrie et de l’écosystème, de la nécessité de la rétrocompatibilité des navigateurs et des normes Web, l’évolution de JavaScript est devenue un flux constant de correctifs, de hacks et de réflexions après coup.

Les travailleurs web JavaScript chargent

Les appareils mobiles d’aujourd’hui sont normalement livrés avec plus de 8 cœurs de processeur, ou plus de 12 cœurs de GPU. Les PROCESSEURS de bureau et de serveur ont jusqu’à 16 cœurs, 32 threads ou plus.

Dans cet environnement, avoir un environnement de programmation ou de script dominant à thread unique est un goulot d’étranglement.

JavaScript Est Mono-thread

Cela signifie que de par leur conception, les moteurs JavaScript — à l’origine les navigateurs – ont un thread d’exécution principal et, pour le dire simplement, le processus ou la fonction B ne peut pas être exécuté tant que le processus ou la fonction A n’est pas terminé. L’interface utilisateur d’une page Web ne répond à aucun autre traitement JavaScript alors qu’elle est occupée à exécuter quelque chose — c’est ce qu’on appelle le blocage DOM.

C’est terriblement inefficace, surtout par rapport à d’autres langues.

Si nous allons dans JS Bin et exécutons ce code dans la console JavaScript du navigateur:

//noprotecti = 0;while (i < 60000) { console.log("The number is " + i); i++;}

… l’ensemble jsbin.com le site Web ne répondra plus jusqu’à ce que le navigateur compte — et se connecte — à 60 000.

Nous ne pourrons pas interagir avec quoi que ce soit sur la page, car le navigateur est occupé.

Maintenant, il s’agit d’un processus informatique relativement peu exigeant, et les applications Web d’aujourd’hui impliquent souvent des tâches beaucoup plus exigeantes.

Nous devons pouvoir calculer des choses en arrière-plan pendant que l’utilisateur interagit de manière transparente avec la page.

Web Workers

Le W3C a publié une première version du standard web workers en 2009. La spécification complète peut être trouvée sur le site Web du Web Hypertext Application Technology Working Group — ou WHATWG — un organisme de normalisation du Web alternatif au W3C.

Web workers est un système ou un protocole asynchrone permettant aux pages Web d’exécuter des tâches en arrière-plan, indépendamment du thread principal et de l’interface utilisateur du site Web. Il s’agit d’un environnement isolé isolé de l’objet window, de l’objet document, d’un accès direct à Internet et mieux adapté aux tâches de calcul longues ou exigeantes.

En dehors des web workers – un système dédié au multithreading —, il existe d’autres moyens de réaliser un traitement asnychrone en JavaScript, tels que les appels Ajax asynchrones et la boucle d’événements.

Pour le démontrer, nous allons revenir à JS Bin et essayer cet extrait:

console.log("A");setTimeout(function(){console.log("B");},2000);console.log("C");setTimeout(function(){console.log("D");},0);console.log("E");setTimeout(function(){console.log("F");},1000);

Lorsque nous exécutons ceci, notre séquence de journal est A, C, E, D, F, B. Le navigateur planifie d’abord les opérations sans délai d’attente, au fur et à mesure, puis il exécute les fonctions setTimeout() dans l’ordre de leurs délais spécifiés respectifs. Cependant, cette asynchronicité ne doit pas être automatiquement confondue avec le multithreading. Selon la machine hôte, il peut souvent s’agir d’une pile à un seul thread des appels dans l’ordre que nous avons expliqué.

Web Workers &Multithreading

Comme l’explique le site Web de référence JavaScript de Mozilla, les web workers sont un « moyen pour le contenu Web d’exécuter des scripts dans des threads d’arrière-plan. »

Nous les utilisons de la manière suivante: nous vérifions la disponibilité du constructeur Worker() dans le navigateur, et s’il est disponible, nous instancions un objet worker, avec l’URL du script comme argument. Ce script sera exécuté sur un thread séparé.

Le script doit être servi à partir du même hôte ou domaine pour des raisons de sécurité, et c’est également la raison pour laquelle les travailleurs Web ne fonctionneront pas si nous ouvrons le fichier localement avec un schéma file://.

if (typeof(Worker) !== "undefined") { worker = new Worker("worker.js");} 

Maintenant, nous définissons ce code dans le fichier worker.js:

i = 0;while (i < 200000) { postMessage("Web Worker Counter: " + i); i++;}

Si vous souhaitez écrire des fichiers de travail Web JavaScript de haute qualité, consultez notre livre, JavaScript: Best Practice.

La séparation des Threads

Une chose importante à noter ici est la séparation de la portée d’exécution window et document dans le thread de la fenêtre principale du navigateur, et de la portée worker.

Pour utiliser le thread worker, ces deux étendues doivent pouvoir communiquer. Pour ce faire, nous utilisons la fonction postMessage() dans le fichier worker.js — pour envoyer des messages au thread principal du navigateur — et l’écouteur worker.onmessage dans le thread principal pour écouter les messages worker.

Nous pouvons également envoyer des messages depuis le thread principal du navigateur vers le thread ou la fonction worker. La seule différence est que nous inversons les choses et appelons worker.postMessage() sur le thread principal, et onmessage sur le thread de travail. Pour citer la référence développeur de Mozilla:

Notez que onmessage et postMessage()doivent être suspendus à l’objet Worker lorsqu’il est utilisé dans le thread de script principal, mais pas lorsqu’il est utilisé dans le travailleur. En effet, à l’intérieur du travailleur, le travailleur est effectivement la portée globale.

Nous pouvons utiliser la méthode terminate() de la même manière, pour mettre fin à l’exécution de notre travailleur.

Avec tout cela à l’esprit, nous arrivons à cet exemple:

index.html

<!DOCTYPE html><html><head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>Web Workers Example</title> <style type="text/css"> body {padding-top:28px;} .output-cont {margin-left:12%; margin-top:28px;} .output-cont h3 {width:200px; height:100%;} .output-cont button {padding:4px 8px; font-size:1.1rem; font-family:sans-serif; } </style></head><body><div class="output-cont"><button onclick="testWorker()">start worker</button><h3></h3><button onclick="terminateWorker()">terminate worker</button></div><br/><div class="output-cont"><button onclick="testMainThread()">start blocking thread</button><h3></h3></div><br/><div class="output-cont"><button onclick="alert('browser responsive!')">test browser responsiveness</button></div> <script> var worker; function testWorker() { if (typeof(Worker) !== "undefined") { if (typeof(worker) == "undefined") { worker = new Worker("worker.js"); } worker.onmessage = function(event) { document.getElementById("workerOutput").innerHTML = event.data; }; } else { document.getElementById("workerOutput").innerHTML = "Web Workers are not supported in your browser"; } } function terminateWorker() { worker.terminate(); worker = undefined; } function testMainThread() { for (var i = 0; i < 200000; i++) { document.getElementById("mainThreadOutput").innerHTML = "Main Thread Counter: " + i; } } </script></body></html>

et le travailleur.js:

i = 0;while (i < 200000) { postMessage("Web Worker Counter: " + i); i++;}

Cela nous donne l’occasion de tester les effets de l’exécution du thread principal sur le comportement et les performances des pages par rapport aux effets du web worker.

Dans ce tutoriel, nous avons utilisé http-server pour servir les fichiers localement.

Test des travailleurs Web JavaScript

Maintenant, nous pouvons voir que le thread de travail ne bloque pas l’interactivité du processus du navigateur principal et que le bouclage de 200 000 nombres n’affecte pas le thread principal. Les nombres de l’élément #workerOutput sont mis à jour à chaque itération.

Le thread de blocage, ou thread principal, lorsqu’il est engagé dans une boucle, bloque toute interactivité (nous avons défini le nombre d’itérations à 200 000 ici, mais ce sera encore plus évident si nous l’augmentons à 2 000 000).

Une autre chose qui nous pointe vers un thread principal bloqué est que le processus de travail met à jour la page à chaque itération et que la boucle du thread principal (celle définie dans index.html) ne met à jour que l’élément #mainThreadOutput lors de la dernière itération.

C’est parce que le navigateur est trop consommé avec le comptage (boucle for) pour pouvoir redessiner le DOM, il ne le fait donc qu’une fois que son activité avec la boucle for est entièrement terminée (à la fin de la boucle).

Conclusion

Dans cet article, nous avons présenté web workers, une technologie qui aide l’industrie du web à suivre les applications Web de plus en plus exigeantes. Ceci est fait en fournissant aux applications Web un moyen de tirer parti des périphériques multi-processeurs et multi-threads en conférant des superpuissances multi-threads à JavaScript.

Les web workers transforment les environnements de navigateur mobile et de bureau en plates-formes applicatives, leur fournissant un environnement d’exécution strict. Cette rigueur peut nous obliger à prévoir la copie d’objets entre plusieurs threads, et à planifier nos applications en tenant compte de ces contraintes.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *