diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
commit | 33058f2b292b3a581333bdfb21b8f671898c5060 (patch) | |
tree | 51c3e392513ec574331b2d3f85c394445ea803c6 /files/fr/web/api/web_workers_api | |
parent | 8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff) | |
download | translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2 translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip |
initial commit
Diffstat (limited to 'files/fr/web/api/web_workers_api')
4 files changed, 1304 insertions, 0 deletions
diff --git a/files/fr/web/api/web_workers_api/advanced_concepts_and_examples/index.html b/files/fr/web/api/web_workers_api/advanced_concepts_and_examples/index.html new file mode 100644 index 0000000000..44716be46c --- /dev/null +++ b/files/fr/web/api/web_workers_api/advanced_concepts_and_examples/index.html @@ -0,0 +1,422 @@ +--- +title: Concepts avancés et exemples +slug: Web/API/Web_Workers_API/Advanced_concepts_and_examples +translation_of: Web/API/Web_Workers_API/Using_web_workers +--- +<div class="summary"> +<p>Cet article fournit de nombreux détails et maints exemples pour illustrer les concepts avancés des web workers.</p> +</div> + +<h2 id="Passage_de_données_copie_et_non_partage">Passage de données : copie, et non partage</h2> + +<p>Les données passées entre la page principale et les workers sont <strong>copiées</strong>, et non partagées. Les objets sont sérialisées au moment où ils sont confiés au worker, et consécutivement désérialisés à l'autre bout. La page et le worker <strong>ne partagent pas la même instance</strong>, ainsi au final <strong>une copie</strong> est créée de chaque côté. La plupart des navigateurs implémentent cette caractéristique en tant que <a href="/en/DOM/The_structured_clone_algorithm" title="The structured clone algorithm">clonage structuré</a>.</p> + +<p>Avant de poursuivre, créons à des fins didactiques une fonction nommée <code>emulateMessage()</code>, avec pour objectif de simuler le comportement d'une valeur qui est <em>clonée et non partagée</em> durant le passage du <code>worker</code> à la page principale ou inversement :</p> + +<pre class="brush: js">function emulateMessage (vVal) { + return eval("(" + JSON.stringify(vVal) + ")"); +} + +// Tests + +// test #1 +var example1 = new Number(3); +alert(typeof example1); // objet +alert(typeof emulateMessage(example1)); // nombre + +// test #2 +var example2 = true; +alert(typeof example2); // booléen +alert(typeof emulateMessage(example2)); // booléen + +// test #3 +var example3 = new String("Hello World"); +alert(typeof example3); // objet +alert(typeof emulateMessage(example3)); // chaîne de caractères + +// test #4 +var example4 = { + "name": "John Smith", + "age": 43 +}; +alert(typeof example4); // objet +alert(typeof emulateMessage(example4)); // objet + +// test #5 +function Animal (sType, nAge) { + this.type = sType; + this.age = nAge; +} +var example5 = new Animal("Cat", 3); +alert(example5.constructor); // Animal +alert(emulateMessage(example5).constructor); // Objet</pre> + +<p>Une valeur qui est clonée et non partagée est appelée <em>message</em>. Comme vous le savez probablement dès à présent, les <em>messages</em> peuvent être envoyés à et à partir du thread principal en utilisant <code>postMessage()</code>, et l'attribut {{domxref("MessageEvent.data", "data")}} de l'événement <code>message</code> contient les données retournées par le worker.</p> + +<p><strong>example.html </strong>(la page principale) :</p> + +<pre class="brush: js">var myWorker = new Worker("my_task.js"); + +myWorker.onmessage = function (oEvent) { + console.log("Worker said : " + oEvent.data); +}; + +myWorker.postMessage("ali");</pre> + +<p><strong>my_task.js</strong> (leworker) :</p> + +<pre class="brush: js">postMessage("I\'m working before postMessage(\'ali\')."); + +onmessage = function (oEvent) { + postMessage("Hi " + oEvent.data); +};</pre> + +<p>L'algorithme de <a href="/en-US/docs/Web/Guide/DOM/The_structured_clone_algorithm" style="line-height: 1.572;" title="The structured clone algorithm">clonage structurée</a> peut accepter du JSON et quelques autres choses impossibles en JSON — comme les références circulaires.</p> + +<h3 id="Exemples_de_passages_de_données">Exemples de passages de données</h3> + +<h4 id="Exemple_1_Créer_un_eval()_asynchrone_générique">Exemple #1 : Créer un "<code>eval() </code>asynchrone" générique</h4> + +<p>L'exemple suivant montre comment utiliser un worker afin d'exécuter <strong>de manière asynchrone</strong> n'importe quel code JavaScript permis dans un worker, au moyen d'une méthode <a href="/en-US/docs/JavaScript/Reference/Global_Objects/eval" title="/en-US/docs/JavaScript/Reference/Global_Objects/eval"><code>eval()</code></a> appelée dans le worker :</p> + +<pre class="brush: js">// Syntaxe : asyncEval(code[, listener]) + +var asyncEval = (function () { + + var aListeners = [], oParser = new Worker("data:text/javascript;charset=US-ASCII,onmessage%20%3D%20function%20%28oEvent%29%20%7B%0A%09postMessage%28%7B%0A%09%09%22id%22%3A%20oEvent.data.id%2C%0A%09%09%22evaluated%22%3A%20eval%28oEvent.data.code%29%0A%09%7D%29%3B%0A%7D"); + + oParser.onmessage = function (oEvent) { + if (aListeners[oEvent.data.id]) { aListeners[oEvent.data.id](oEvent.data.evaluated); } + delete aListeners[oEvent.data.id]; + }; + + + return function (sCode, fListener) { + aListeners.push(fListener || null); + oParser.postMessage({ + "id": aListeners.length - 1, + "code": sCode + }); + }; + +})();</pre> + +<p>La data URI est équivalente à une requête réseau, avec la réponse suivante :</p> + +<pre>onmessage = function (oEvent) { + postMessage({ + "id": oEvent.data.id, + "evaluated": eval(oEvent.data.code) + }); +}</pre> + +<p>Exemples d'utilisation :</p> + +<pre class="brush: js">// message d'alerte asynchrone... +asyncEval("3 + 2", function (sMessage) { + alert("3 + 2 = " + sMessage); +}); + +// affichage asynchrone d'un message... +asyncEval("\"Hello World!!!\"", function (sHTML) { + document.body.appendChild(document.createTextNode(sHTML)); +}); + +// néant asynchrone... +asyncEval("(function () {\n\tvar oReq = new XMLHttpRequest();\n\toReq.open(\"get\", \"http://www.mozilla.org/\", false);\n\toReq.send(null);\n\treturn oReq.responseText;\n})()");</pre> + +<h4 id="Exemple_2_passage_avancé_de_données_JSON_et_création_d'un_système_d'échange">Exemple #2 : passage avancé de données JSON et création d'un système d'échange</h4> + +<p>Si vous devez passer des données complexes et appeler différentes fonctions à la fois dans la page principale et dans le worker, vous pouvez créer un système comme suit.</p> + +<p><strong>example.html</strong> (la page principale) :</p> + +<pre class="brush: html"><!doctype html> +<html> +<head> +<meta charset="UTF-8" /> +<title>MDN Example - Queryable worker</title> +<script type="text/javascript"> + /* + QueryableWorker instances methods: + * sendQuery(queryable function name, argument to pass 1, argument to pass 2, etc. etc): calls a Worker's queryable function + * postMessage(string or JSON Data): see Worker.prototype.postMessage() + * terminate(): terminates the Worker + * addListener(name, function): adds a listener + * removeListener(name): removes a listener + QueryableWorker instances properties: + * defaultListener: the default listener executed only when the Worker calls the postMessage() function directly + */ + function QueryableWorker (sURL, fDefListener, fOnError) { + var oInstance = this, oWorker = new Worker(sURL), oListeners = {}; + this.defaultListener = fDefListener || function () {}; + oWorker.onmessage = function (oEvent) { + if (oEvent.data instanceof Object && oEvent.data.hasOwnProperty("vo42t30") && oEvent.data.hasOwnProperty("rnb93qh")) { + oListeners[oEvent.data.vo42t30].apply(oInstance, oEvent.data.rnb93qh); + } else { + this.defaultListener.call(oInstance, oEvent.data); + } + }; + if (fOnError) { oWorker.onerror = fOnError; } + this.sendQuery = function (/* nom de la fonction requêtable, argument à passer 1, argument à passer 2, etc. etc */) { + if (arguments.length < 1) { throw new TypeError("QueryableWorker.sendQuery - not enough arguments"); return; } + oWorker.postMessage({ "bk4e1h0": arguments[0], "ktp3fm1": Array.prototype.slice.call(arguments, 1) }); + }; + this.postMessage = function (vMsg) { + //Je ne pense pas qu'il y ait besoin d'appeler la méthode call() + //que diriez-vous tout simplement de oWorker.postMessage(vMsg); + //le même cas se pose avec terminate + //bien, juste un peu plus vite, aucune recherche dans la chaîne des prototypes + Worker.prototype.postMessage.call(oWorker, vMsg); + }; + this.terminate = function () { + Worker.prototype.terminate.call(oWorker); + }; + this.addListener = function (sName, fListener) { + oListeners[sName] = fListener; + }; + this.removeListener = function (sName) { + delete oListeners[sName]; + }; + }; + + // votre worker "queryable" personnalisé + var oMyTask = new QueryableWorker("my_task.js" /* , votreEcouteurDeMessageParDefautIci [optional], votreEcouteurDErreurIci [optional] */); + + // vos "écouteurs" personnalisés + + oMyTask.addListener("printSomething", function (nResult) { + document.getElementById("firstLink").parentNode.appendChild(document.createTextNode(" The difference is " + nResult + "!")); + }); + + oMyTask.addListener("alertSomething", function (nDeltaT, sUnit) { + alert("Worker waited for " + nDeltaT + " " + sUnit + " :-)"); + }); +</script> +</head> +<body> + <ul> + <li><a id="firstLink" href="javascript:oMyTask.sendQuery('getDifference', 5, 3);">What is the difference between 5 and 3?</a></li> + <li><a href="javascript:oMyTask.sendQuery('waitSomething');">Wait 3 seconds</a></li> + <li><a href="javascript:oMyTask.terminate();">terminate() the Worker</a></li> + </ul> +</body> +</html></pre> + +<p><strong>my_task.js</strong> (le worker) :</p> + +<pre class="brush: js">// vos fonctions PRIVEES personnalisées + +function myPrivateFunc1 () { + // instructions à exécuter +} + +function myPrivateFunc2 () { + // instructions à exécuter +} + +// etc. etc. + +// vos fonctions PUBLIQUES personnalisées (i.e. requêtables depuis la page principale) + +var queryableFunctions = { + // exemple #1 : obtenir la différence entre deux nombres : + getDifference: function (nMinuend, nSubtrahend) { + reply("printSomething", nMinuend - nSubtrahend); + }, + // exemple #2 : attendre trois secondes + waitSomething: function () { + setTimeout(function() { reply("alertSomething", 3, "seconds"); }, 3000); + } +}; + +// fonctions système + +function defaultQuery (vMsg) { + // votre fonction PUBLIQUE par défaut est exécutée seulement lorsque la page principale appelle la méthode queryableWorker.postMessage() directement + // instructions à exécuter +} + +function reply (/* listener name, argument to pass 1, argument to pass 2, etc. etc */) { + if (arguments.length < 1) { throw new TypeError("reply - not enough arguments"); return; } + postMessage({ "vo42t30": arguments[0], "rnb93qh": Array.prototype.slice.call(arguments, 1) }); +} + +onmessage = function (oEvent) { + if (oEvent.data instanceof Object && oEvent.data.hasOwnProperty("bk4e1h0") && oEvent.data.hasOwnProperty("ktp3fm1")) { + queryableFunctions[oEvent.data.bk4e1h0].apply(self, oEvent.data.ktp3fm1); + } else { + defaultQuery(oEvent.data); + } +};</pre> + +<p>Il est possible d'échanger le contenu de chaque message page principale -> worker et worker -> page principale.</p> + +<h3 id="Passage_de_données_par_transfert_de_propriété_(objets_transférables)">Passage de données par transfert de propriété (objets transférables)</h3> + +<p>Google Chrome 17+ et Firefox 18+ proposent une manière additionnelle de passer certains types d'objets (les objets <span class="external">transférables, c'est-à-dire les objets implémentant l'interface {{domxref("Transferable")}}</span>) vers ou à partir d'un worker avec une haute performance. Les objets transférables sont transférés d'un contexte vers un autre sans aucune opération de copie, ce qui conduit à d'énormes gains de performance lorsque de gros ensembles de données sont envoyés. Considérez la chose comme un passage par référence si vous venez du monde C/C++. Cependant, contrairement au passage par référence, la 'version' issue du contexte appelant n'est plus disponible une fois transférée. Sa propriété est transférée au nouveau contexte. Par exemple, lors du transfert d'un {{domxref("ArrayBuffer")}} à partir de votre application principale vers le script d'un worker, le {{domxref("ArrayBuffer")}} original est nettoyé et définitivement inutilisable. Son contenu est (tout à fait littéralement) transféré au contexte du worker.</p> + +<pre class="brush: js">// Crée un "fichier" de 32MB et le remplit. +var uInt8Array = new Uint8Array(1024*1024*32); // 32MB +for (var i = 0; i < uInt8Array.length; ++i) { + uInt8Array[i] = i; +} + +worker.postMessage(uInt8Array.buffer, [uInt8Array.buffer]); +</pre> + +<div class="note"> +<p><strong>Remarque </strong>: pour plus d'information sur les objets transférables, la performance et la détection de fonctionnalité de cette méthode, lisez <a href="http://updates.html5rocks.com/2011/12/Transferable-Objects-Lightning-Fast">Transferable Objects: Lightning Fast!</a> sur HTML5 Rocks.</p> +</div> + +<h2 id="Workers_embarqués">Workers embarqués</h2> + +<p>Il n'y a pas une manière "officielle" d'embarquer le code d'un worker dans une page web, comme les éléments {{ HTMLElement("script") }} le font pour les scripts normaux. Mais un élément {{ HTMLElement("script") }} qui n'aurait pas d'attribut <code>src</code> et dont l'attribut <code>type</code> n'identifierait pas un type MIME exécutable peut être considéré comme un élément de bloc de données dont JavaScript peut faire usage. Les "blocs de données" sont une caractéristique plus générale d'HTML5 qui peuvent contenir presque n'importe quelles données textuelles. Ainsi, un worker pourrait être embarqué de cette façon :</p> + +<pre class="brush: html"><!DOCTYPE html> +<html> +<head> +<meta charset="UTF-8" /> +<title>MDN Example - Embedded worker</title> +<script type="text/js-worker"> + // Ce script NE SERA PAS traité par les moteurs JS parce que son type MIME est text/js-worker. + var myVar = "Hello World!"; + // Le reste du code de votre worker commence ici. +</script> +<script type="text/javascript"> + // Ce script SERA analysé par les moteurs JS engines parce que son type MIME est text/javascript. + function pageLog (sMsg) { + // Utilisation d'un fragment : le navigateur réaffichera/réorganisera le DOM seulement une fois. + var oFragm = document.createDocumentFragment(); + oFragm.appendChild(document.createTextNode(sMsg)); + oFragm.appendChild(document.createElement("br")); + document.querySelector("#logDisplay").appendChild(oFragm); + } +</script> +<script type="text/js-worker"> + // Ce script NE SERA PAS traité par les moteurs JS parce que son type MIME est text/js-worker. + onmessage = function (oEvent) { + postMessage(myVar); + }; + // Le reste du code de votre worker commence ici. +</script> +<script type="text/javascript"> + // Ce script SERA analysé par les moteurs JS engines parce que son type MIME est text/javascript. + + // Dans le passé... : + // blob builder a existé + // ...mais nous utilisons désormais Blob...: + var blob = new Blob(Array.prototype.map.call(document.querySelectorAll("script[type=\"text\/js-worker\"]"), function (oScript) { return oScript.textContent; }),{type: "text/javascript"}); + + // Création d'une nouvelle propriété document.worker contenant tous nos scripts "text/js-worker". + document.worker = new Worker(window.URL.createObjectURL(blob)); + + document.worker.onmessage = function (oEvent) { + pageLog("Received: " + oEvent.data); + }; + + // Démarrage du worker. + window.onload = function() { document.worker.postMessage(""); }; +</script> +</head> +<body><div id="logDisplay"></div></body> +</html></pre> + +<p>Le worker embarqué est maintenant imbriqué dans une nouvelle propriété personnalisée <code>document.worker</code>.</p> + +<h2 id="Exemples">Exemples</h2> + +<p>Cette section fournit plusieurs exemples sur la façon d'utiliser les workers DOM.</p> + +<h3 id="Réaliser_des_calculs_en_arrière-plan">Réaliser des calculs en arrière-plan</h3> + +<p>Les workers sont principalement utiles pour permettre à votre code de réaliser des calculs très consommateur en CPU sans bloquer le thread de l'interface utilisateur. Dans cet exemple, un worker est utilisé pour calculer la suite de Fibonacci.</p> + +<h4 id="Le_code_JavaScript">Le code JavaScript</h4> + +<p>Le code JavaScript suivant est stocké dans le fichier "fibonacci.js" référencé par le fichier HTML dans la prochaine section.</p> + +<pre class="brush: js">var results = []; + +function resultReceiver(event) { + results.push(parseInt(event.data)); + if (results.length == 2) { + postMessage(results[0] + results[1]); + } +} + +function errorReceiver(event) { + throw event.data; +} + +onmessage = function(event) { + var n = parseInt(event.data); + + if (n == 0 || n == 1) { + postMessage(n); + return; + } + + for (var i = 1; i <= 2; i++) { + var worker = new Worker("fibonacci.js"); + worker.onmessage = resultReceiver; + worker.onerror = errorReceiver; + worker.postMessage(n - i); + } + };</pre> + +<p>Le worker affecte à la propriété <code>onmessage</code> une fonction qui recevra les messages envoyés lorsque la méthode <code>postMessage()</code> de l'objet worker est appelée (remarquez que cela diffère de définir une <em>variable</em> globale de ce nom, ou de définir une <em>fonction</em> avec ce nom. <code>var onmessage</code> <code>et function onmessage</code> définissent des propriétés globales avec ces noms, mais elles n'enregistrent pas la fonction pour recevoir les messages envoyés par la page web qui a créé le worker). Au démarrage de la récursion, il engendre ainsi de nouvelles copies de lui-même pour gérer chacune des itérations du calcul.</p> + +<h4 id="Le_code_HTML">Le code HTML</h4> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="UTF-8" /> + <title>Test threads fibonacci</title> + </head> + <body> + + <div id="result"></div> + + <script language="javascript"> + + var worker = new Worker("fibonacci.js"); + + worker.onmessage = function(event) { + document.getElementById("result").textContent = event.data; + dump("Got: " + event.data + "\n"); + }; + + worker.onerror = function(error) { + dump("Worker error: " + error.message + "\n"); + throw error; + }; + + worker.postMessage("5"); + + </script> + </body> +</html> +</pre> + +<p>La page web crée un élément <code>div</code> avec l'ID <code>result</code> , qui sera utilisé pour afficher le résultat, puis engendre le worker. Après création du worker, le gestionnaire <code>onmessage</code> est configuré pour afficher les résultats en renseignant le contenu de l'élément <code>div</code>, et le gestionnaire <code>onerror</code> est configuré pour <a class="external" href="/en/Debugging_JavaScript#dump()" title="https://developer.mozilla.org/editor/fckeditor/core/editor/en/Debugging_JavaScript#dump()">capturer</a> le message d'erreur.</p> + +<p>Finalement, un message est envoyé au worker pour le démarrer.</p> + +<p><a class="external" href="/samples/workers/fibonacci" title="https://developer.mozilla.org/samples/workers/fibonacci/">Tester cet exemple</a>.</p> + +<h3 id="Réaliser_des_ES_web_en_arrière-plan">Réaliser des E/S web en arrière-plan</h3> + +<p>Vous pouvez trouver un tel exemple dans l'article <a class="internal" href="/En/Using_workers_in_extensions" title="En/Using workers in extensions">Using workers in extensions</a> .</p> + +<h3 id="Répartir_des_tâches_entre_plusieurs_workers">Répartir des tâches entre plusieurs workers</h3> + +<p>Les ordinateurs multi-coeur étant de plus en plus répandus, il est souvent utile de répartir le calcul de tâches complexes entre différents workers afin de tirer partie des coeurs de ces multiprocesseurs.</p> + +<h2 id="Voir_aussi">Voir aussi</h2> + +<ul> + <li><a href="/en-US/docs/Web/API/Web_Workers_API">API Web Workers</a></li> + <li><a href="/en-US/docs/Web/API/Web_Workers_API/basic_usage">Utilisation des web workers</a></li> +</ul> diff --git a/files/fr/web/api/web_workers_api/algorithme_clonage_structure/index.html b/files/fr/web/api/web_workers_api/algorithme_clonage_structure/index.html new file mode 100644 index 0000000000..dfb8c20bf9 --- /dev/null +++ b/files/fr/web/api/web_workers_api/algorithme_clonage_structure/index.html @@ -0,0 +1,153 @@ +--- +title: L’algorithme de clonage structuré +slug: Web/API/Web_Workers_API/algorithme_clonage_structure +translation_of: Web/API/Web_Workers_API/Structured_clone_algorithm +--- +<p>L’algorithme de clonage structuré est un nouvel algorithme <a class="external" href="http://www.w3.org/html/wg/drafts/html/master/infrastructure.html#safe-passing-of-structured-data" title="http://www.w3.org/TR/html5/common-dom-interfaces.html#safe-passing-of-structured-data">défini par la spécification HTML5</a> pour sérialiser les objets JavaScript complexes. Il est plus puissant que <a href="/en/JSON" title="en/JSON">JSON</a> en cela qu’il supporte la sérialisation d’objets contenant des graphes cycliques — des objets peuvent faire référence à des objets faisant référence à d’autres objets dans le même graphe. De plus, dans certains cas, l’algorithme de clonage structuré peut être plus efficace que JSON.</p> + +<p>L’algorithme, essentiellement, parcourt tous les champs de l’objet original, copiant les valeurs de chaque champ dans un nouvel objet. Si un champ est lui-même un objet avec des champs, ces champs sont parcourus de manière récursive jusqu’à ce que chaque champ et sous-champ aient été copié dans le nouvel objet.</p> + +<h2 id="Avantages_par_rapport_à_JSON">Avantages par rapport à JSON</h2> + +<p>Il y a quelques avantages notables à utiliser l’algorithme de clonage structuré plutôt que JSON :</p> + +<ul> + <li>Le clonage structuré peut copier des objets <a href="/en/JavaScript/Reference/Global_Objects/RegExp" title="en/JavaScript/Reference/Global Objects/regexp"><code>RegExp</code></a>.</li> + <li>Le clonage structuré peut copier des objets {{ domxref("Blob") }}, {{ domxref("File") }} et {{ domxref("FileList") }}.</li> + <li>Le clonage structuré peut copier des objets {{ domxref("ImageData") }}. Les dimensions du {{ domxref("CanvasPixelArray") }} du clone correspondront à celles de l’original, et il recevra une copie des mêmes données de pixels.</li> + <li>Le clonage structuré copie correctement les objets contenant des graphes de références cycliques.</li> +</ul> + +<h2 id="Ce_qui_ne_marche_pas_avec_le_clonage_structuré">Ce qui ne marche pas avec le clonage structuré</h2> + +<ul> + <li>Les objets <a href="/en/JavaScript/Reference/Global_Objects/Error" title="en/JavaScript/Reference/Global Objects/Error"><code>Error</code></a> et <a href="/en/JavaScript/Reference/Global_Objects/Function" title="en/JavaScript/Reference/Global Objects/Function"><code>Function</code></a> ne peuvent pas être copiés par l’algorithme de clonage structuré ; toute tentative de le faire émettra une exception <code>DATA_CLONE_ERR</code>.</li> + <li>De la même manière, toute tentative de cloner des nœuds DOM émettra une exception <code>DATA_CLONE_ERR</code>.</li> + <li>Certains paramètres d’objets ne sont pas préservés : + <ul> + <li>Le champ <code>lastIndex</code> des objets <a href="/en/JavaScript/Reference/Global_Objects/RegExp" title="en/JavaScript/Reference/Global Objects/regexp"><code>RegExp</code></a> n’est pas préservé.</li> + <li>Les descripteurs de propriétés, accesseurs et mutateurs (ainsi que les fonctionnalités de métadonnées similaires) ne sont pas copiés. Par exemple, si un objet est marqué en lecture seule <em>via</em> un descripteur de propriété, il sera en lecture et écriture dans le clone, car c’est la condition par défaut.</li> + <li>La chaîne de prototypes n’est ni parcourue, ni copiée.</li> + </ul> + </li> +</ul> + +<h2 id="Types_supportés">Types supportés</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Type d’objet</th> + <th scope="col">Notes</th> + </tr> + </thead> + <tbody> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Data_structures#Primitive_values">Tous types primitifs</a></td> + <td>À l’exception des symboles</td> + </tr> + <tr> + <td>Objet <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean">Booléen</a></td> + <td> </td> + </tr> + <tr> + <td>Objet String</td> + <td> </td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date">Date</a></td> + <td> </td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp">RegExp</a></td> + <td>Le champ <code>lastIndex</code> n’est pas préservé</td> + </tr> + <tr> + <td>{{ domxref("Blob") }}</td> + <td> </td> + </tr> + <tr> + <td>{{ domxref("File") }}</td> + <td> </td> + </tr> + <tr> + <td>{{ domxref("FileList") }}</td> + <td> </td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/API/ArrayBuffer">ArrayBuffer</a></td> + <td> </td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/API/ArrayBufferView">ArrayBufferView</a></td> + <td>Ce qui implique tous les <a href="/en-US/docs/Web/JavaScript/Typed_arrays">tableaux typés</a> tels que <code>Int32Array</code>, etc.</td> + </tr> + <tr> + <td>{{ domxref("ImageData") }}</td> + <td> </td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array">Array</a></td> + <td> </td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object">Object</a></td> + <td>Inclut seulement les objets plats (par ex. depuis un objet littéral)</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map">Map</a></td> + <td> </td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set">Set</a></td> + <td> </td> + </tr> + </tbody> +</table> + +<h2 id="Alternative_copie_profonde">Alternative : copie profonde</h2> + +<p>Si vous voulez une <strong>copie profonde</strong> d’un objet (c’est-à-dire une copie récursive de toutes les propriétés imbriquées, en parcourant la chaîne des prototypes), vous devez employer une autre approche. Ce qui suit est un exemple possible.</p> + +<pre class="brush: js">function clone(objectToBeCloned) { + // Cas basique. + if (!(objectToBeCloned instanceof Object)) { + return objectToBeCloned; + } + + var objectClone; + + // Filtre les objets spéciaux. + var Constructor = objectToBeCloned.constructor; + switch (Constructor) { + // Implémenter d’autres objets spéciaux ici. + case RegExp: + objectClone = new Constructor(objectToBeCloned); + break; + case Date: + objectClone = new Constructor(objectToBeCloned.getTime()); + break; + default: + objectClone = new Constructor(); + } + + // Clone chaque propriété. + for (var prop in objectToBeCloned) { + objectClone[prop] = clone(objectToBeCloned[prop]); + } + + return objectClone; +} +</pre> + +<div class="note"><strong> Note :</strong> Cet algorithme ne prend en charge que les objets spéciaux <a href="/en/JavaScript/Reference/Global_Objects/RegExp" title="RegExp"><code>RegExp</code></a>, <a href="/en/JavaScript/Reference/Global_Objects/Array" title="Array"><code>Array</code></a> et <a href="/en/JavaScript/Reference/Global_Objects/Date" title="Date"><code>Date</code></a>. Vous pouvez implémenter d’autres cas spéciaux selon vos besoins.</div> + +<h2 id="Voir_aussi">Voir aussi</h2> + +<ul> + <li><a class="external" href="http://www.w3.org/TR/html5/infrastructure.html#safe-passing-of-structured-data" title="http://www.w3.org/TR/html5/common-dom-interfaces.html#safe-passing-of-structured-data">Spécification HTML5 : Passage sécurisé de données structurées</a></li> + <li>{{ domxref("window.history") }}</li> + <li>{{ domxref("window.postMessage()") }}</li> + <li><a href="/en-US/docs/Web/API/Web_Workers_API">Web Workers</a></li> + <li><a href="/en-US/docs/Components.utils.cloneInto">Components.utils.cloneInto</a></li> +</ul> diff --git a/files/fr/web/api/web_workers_api/index.html b/files/fr/web/api/web_workers_api/index.html new file mode 100644 index 0000000000..e218058f53 --- /dev/null +++ b/files/fr/web/api/web_workers_api/index.html @@ -0,0 +1,96 @@ +--- +title: API Web Workers +slug: Web/API/Web_Workers_API +tags: + - API + - DOM +translation_of: Web/API/Web_Workers_API +--- +<article class="approved"> +<header>{{DefaultAPISidebar("Web Workers API")}}</header> +</article> + +<p>Les <strong>Web Workers</strong> sont un mécanisme grâce auquel les instructions d'un script peuvent être exécutés dans un thread en arrière-plan séparé du thread d'exécution principal d'une application web. Cela a pour avantage qu'un traitement laborieux peut être réalisé dans un thread séparé, permettant au thread principal (généralement l'interface utilisateur) de fonctionner sans blocage ni ralentissement.</p> + +<h2 id="Concepts_et_utilisation_des_Web_Workers">Concepts et utilisation des Web Workers</h2> + +<p>Un worker est un objet créé en utilisant un constructeur (e.g. {{domxref("Worker.Worker", "Worker()")}}) qui exécute un fichier JavaScript nommé — ce fichier contient le code que doit exécuter le thread du worker; les workers s'exécutent dans un autre contexte global qui est différent du contexte actuel {{domxref("window")}}. Ce contexte est représenté par un objet {{domxref("DedicatedWorkerGlobalScope")}} dans le cas des workers dédiés (workers standards utilisés par un script unique; les workers partagés utilisent {{domxref("SharedWorkerGlobalScope")}}).</p> + +<p>Vous pouvez exécuter quelque code que ce soit à l'intérieur du thread du worker, avec quelques exceptions cependant. Par exemple, vous ne pouvez pas directement manipuler le DOM à partir d'un worker, ou utiliser des méthodes et des propriétés par défaut de l'objet {{domxref("window")}}. Mais vous pouvez utiliser un grand nombre des éléments disponibles sous <code>window</code>, comprenant les <a href="/fr/docs/WebSockets">WebSockets</a>, et les mécanismes de stockage de données tels qu'<a href="/fr/docs/IndexedDB">IndexedDB</a> et l'<a href="/en-US/docs/Web/API/Data_Store_API">API Data Store</a> spécifique à Firefox OS. Consultez <a href="/fr/docs/Web/API/Worker/Functions_and_classes_available_to_workers">Les fonctions et classes accessibles aux workers</a> pour plus de détails.</p> + +<p>Les données sont envoyées entre les workers et le thread principal au moyen d'un sytème de messages — des deux côtés les messages sont envoyés en utilisant la méthode <code>postMessage()</code>, et la réponse leur parvient au moyen du gestionnaire d'événement <code>onmessage</code> (le message est contenu dans l'attribut <code>data</code> de l'événement {{event("Message")}}.) Les données sont copiées plutôt que partagées.</p> + +<p>Les workers peuvent à leur tour engendrer de nouveaux workers, aussi longtemps que ces workers partagent la même origine que la page parente. De plus, les workers peuvent utiliser <a class="internal" href="/fr/docs/Web/API/XMLHttpRequest"><code>XMLHttpRequest</code></a> pour les E/S réseau, à l'exception que les attributs <code>responseXML</code> et <code>channel</code> de <code>XMLHttpRequest</code> retournent toujours <code>null</code>.</p> + +<p>En plus des workers dédiés, il y a d'autres types de worker :</p> + +<ul> + <li>Les workers partagés sont des workers qui peuvent être utilisés par de multiples scripts s'exécutant dans différentes fenêtres, IFrames, etc., aussi longtemps qu'ils sont dans le même domaine que le worker. Leur fonctionnement est un petit plus complexe que les workers dédiés — les scripts doivent communiquer via un port actif. Consultez {{domxref("SharedWorker")}} pour plus de détails.</li> + <li>Les <a href="/en-US/docs/Web/API/ServiceWorker_API">ServiceWorkers</a> fonctionnent essentiellement comme des serveurs proxy placés entre des applications web, et le navigateur et le réseau (lorsque disponibles). Ils sont destinés (entre autres choses) à permettre la création de véritables expériences déconnectées, interceptant les requêtes du réseau et prenant des décisions appropriées en fonction de la disponibilité du réseau et de la mise à jours des ressources situées sur le serveur. Ils permettront aussi d'accéder à des notifications poussées (push) et à des APIs synchronisées en arrière-plan.</li> + <li>Les Workers Chrome sont un type de worker spécifique à Firefox que vous pouvez utiliser si vous développez des extensions et que vous voulez y utiliser des workers et avoir accès aux <a href="/fr/docs/Mozilla/js-ctypes">js-ctypes</a> dans votre worker. Consulter {{domxref("ChromeWorker")}} pour plus de détails. </li> + <li>Les <a href="/fr/docs/Web/API/Web_Audio_API#Audio_Workers">Audio Workers</a> donne la possibilité d'effectuer directement dans le contexte d'un worker web un traitement audio scripté.</li> +</ul> + +<div class="blockIndicator note"> +<p>Remarque: Selon les <a href="https://html.spec.whatwg.org/multipage/workers.html#runtime-script-errors-2">Spécifications de Web Worker</a>, les erreurs dans les workers ne devraient pas déborder (voir {{bug(1188141)}}). Cela a été implémenté dans Firefox 42.</p> +</div> + +<h2 id="Les_interfaces_Web_Worker">Les interfaces Web Worker</h2> + +<dl> + <dt>{{domxref("AbstractWorker")}}</dt> + <dd>Propriétés et méthodes abstraites communes à tous les types de workers (i.e. {{domxref("Worker")}} ou {{domxref("SharedWorker")}}).</dd> + <dt>{{domxref("Worker")}}</dt> + <dd>Représente le thread d'un worker en cours d'exécution, vous permettant de passer des messages au code du worker en cours d'exécution.</dd> + <dt>{{DOMxRef("WorkerLocation")}}</dt> + <dd>Défini la localisation du scripte exécuté par le <a href="/fr/docs/Web/API/Worker">Worker</a>.</dd> + <dt>{{domxref("SharedWorker")}}</dt> + <dd>Représente un type spécifique de worker qui peut être <em>accédé</em> à partir de plusieurs contextes de navigation, à savoir plusieurs fenêtres, iframes ou même workers.</dd> + <dt>{{domxref("WorkerGlobalScope")}}</dt> + <dd>Représente le contexte générique de tout worker (il joue le même rôle que {{domxref("Window")}} pour un contenu web normal). Les différents types de worker ont un contexte d'objets qui hérite de cette interface et ajoute des fonctionnalités supplémentaires.</dd> + <dt>{{domxref("DedicatedWorkerGlobalScope")}}</dt> + <dd>Représente le contexte d'un worker dédié, héritant de {{domxref("WorkerGlobalScope")}} et ajoutant des fonctionnalités spécifiques.</dd> + <dt>{{domxref("SharedWorkerGlobalScope")}}</dt> + <dd>Représente le contexte d'un worker partagé, héritant de {{domxref("WorkerGlobalScope")}} et ajoutant des fonctionnalités spécifiques.</dd> + <dt>{{domxref("WorkerNavigator")}}</dt> + <dd>Représente l'identité et l'état de l'agent utilisateur (le client):</dd> +</dl> + +<h2 id="Exemples">Exemples</h2> + +<p>Nous avons créé deux simples démos pour illustrer des usages basiques :</p> + +<ul> + <li><a href="https://github.com/mdn/simple-web-worker">Exemple basique d'un worker dédié</a> (<a href="http://mdn.github.io/simple-web-worker/">lancer le worker dédié</a>).</li> + <li><a href="https://github.com/mdn/simple-shared-worker">Exemple basique d'un worker partagé</a> (<a href="http://mdn.github.io/simple-shared-worker/">lancer le worker partagé</a>).</li> +</ul> + +<p>Vous pouvez obtenir plus d'informations sur le fonctionnement de ces démos dans notre <a href="/fr/docs/Utilisation_des_web_workers">guide d'utilisation des web workers</a>.</p> + +<h2 id="Spécifications">Spécifications</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">Spécification</th> + <th scope="col">Statut</th> + <th scope="col">Commentaire</th> + </tr> + <tr> + <td>{{SpecName("HTML WHATWG", "workers.html#workers", "Web Workers")}}</td> + <td>{{Spec2("HTML WHATWG")}}</td> + <td>Définition initiale.</td> + </tr> + </tbody> +</table> + +<h2 id="Voir_aussi">Voir aussi</h2> + +<ul> + <li><a href="/fr/docs/Utilisation_des_web_workers">Utilisation des web workers</a></li> + <li><a href="/fr/docs/Web/API/Worker">L'interface Worker</a></li> + <li><a href="/fr/docs/Web/API/SharedWorker">L'interface SharedWorker</a></li> + <li><a href="/en-US/docs/Web/API/ServiceWorker_API">L'API ServiceWorker</a></li> + <li><a href="/fr/docs/Web/API/Worker/Functions_and_classes_available_to_workers">Les fonctions et classes accessibles aux workers</a></li> + <li><a href="/en-US/docs/Web/API/ChromeWorker">ChromeWorker</a> : pour l'utilisation des workers dans un code privilégié (chrome)</li> +</ul> diff --git a/files/fr/web/api/web_workers_api/utilisation_des_web_workers/index.html b/files/fr/web/api/web_workers_api/utilisation_des_web_workers/index.html new file mode 100644 index 0000000000..b1330f34bf --- /dev/null +++ b/files/fr/web/api/web_workers_api/utilisation_des_web_workers/index.html @@ -0,0 +1,633 @@ +--- +title: Utilisation des web workers +slug: Web/API/Web_Workers_API/Utilisation_des_web_workers +tags: + - Avancé + - Guide + - JavaScript + - Web Workers +translation_of: Web/API/Web_Workers_API/Using_web_workers +--- +<div>{{DefaultAPISidebar("Web Workers API")}}</div> + +<p><span class="seoSummary">Les <em>Web Workers</em> sont un outil permettant au contenu web d'exécuter des scripts dans des tâches (<em>threads</em>) d'arrière-plan. Le <em>thread</em> associé au <em>worker</em> peut réaliser des tâches sans qu'il y ait d'interférence avec l'interface utilisateur. De plus, les <em>web workers</em> peuvent réaliser des opérations d'entrée/sortie grâce à <code><a class="internal" href="/fr/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a></code> (bien que les attributs <code>responseXML</code> et <code>channel</code> soient nécessairement vides dans ces cas). Une fois créé, un <em>worker</em> peut envoyer des messages au code JavaScript qui l'a créé. De même, le script initial peut envoyer des messages au <em>worker</em>. Cette communication s'effectue grâce à des gestionnaires d'évènements.</span> Dans cet article, nous verrons une introduction à l'utilisation des <em>web workers</em>.</p> + +<h2 id="LAPI_Web_Workers">L'API Web Workers</h2> + +<p>Un <em>worker</em> est un objet créé à l'aide d'un constructeur (par exemple {{domxref("Worker.Worker", "Worker()")}}) et qui exécute un fichier JavaScript donné. Ce fichier contient le code qui sera exécuté par le <em>thread</em> du <em>worker</em>. Les <em>workers</em> sont exécutés dans un contexte global qui n'est pas celui du document (généralement {{domxref("window")}}). Aussi, si, dans un <em>worker</em>, on utilise {{domxref("window")}} pour accéder à la portée globale (plutôt que {{domxref("window.self","self")}}), cela provoquera une erreur.</p> + +<p>Le contexte du <em>worker</em> est représenté par un objet {{domxref("DedicatedWorkerGlobalScope")}} pour les <em>workers</em> dédiés et par un objet {{domxref("SharedWorkerGlobalScope")}} sinon. Un <em>worker</em> dédié est uniquement accessible au travers du script qui l'a déclenché tandis qu'un <em>worker</em> partagé peut être utilisé par différents scripts.</p> + +<div class="note"> +<p><strong>Note </strong>: Voir <a href="/fr/docs/Web/API/Web_Workers_API">la page d'entrée pour l'API Web Workers</a> pour consulter la documentation de référence sur les <em>workers</em> et d'autres guides.</p> +</div> + +<p>Il est possible d'exécuter n'importe quel code JavaScript dans le <em>thread</em> du <em>worker</em>, à l'exception des méthodes de manipulation du DOM ou de certaines propriétés et méthodes rattachées à {{domxref("window")}}. On notera cependant qu'on peut tout à fait utiliser certaines API rendues disponibles via <code>window</code> comme les <a href="/fr/docs/Web/API/WebSockets_API">WebSockets</a>, les API de stockage de données telles que <a href="/fr/docs/Web/API/API_IndexedDB">IndexedDB</a>. Pour plus de détails, voir <a href="/fr/docs/Web/API/Worker/Functions_and_classes_available_to_workers">les fonctions et classes disponibles au sein des <em>workers</em></a>.</p> + +<p>Les données sont échangées entre le <em>thread</em> du <em>worker</em> et le <em>thread</em> principal par l'intermédiaire de messages. Chaque partie peut envoyer des messages à l'aide de la méthode <code>postMessage()</code> et réagir aux messages reçus grâce au gestionnaire d'évènement <code>onmessage</code> (le message sera contenu dans l'attribut <code>data</code> de l'évènement {{event("Message")}} associé). Les données sont copiées dans le message, elles ne sont pas partagées.</p> + +<p>Les <em>workers</em> peuvent également déclencher la création d'autres <em>workers</em> tant que ceux-ci restent hébergés sur la même origine que la page parente. De plus, les <em>workers</em> pourront utiliser <a class="internal" href="/fr/docs/Web/API/XMLHttpRequest"><code>XMLHttpRequest</code></a> pour effectuer des opérations réseau mais les attributs <code>responseXML</code> et <code>channel</code> de <code>XMLHttpRequest</code> renverront nécessairement <code>null</code>.</p> + +<h2 id="Les_workers_dédiés">Les <em>workers</em> dédiés</h2> + +<p>Comme indiqué plus haut, un <em>worker</em> dédié n'est accessible qu'au travers du script qui l'a initié. Dans cette section, nous étudierons le code JavaScript de <a href="https://github.com/mdn/simple-web-worker">notre exemple de <em>worker</em> dédié simple</a>. Dans cet exemple, nous souhaitons multiplier deux nombres. Ces nombres sont envoyés à un <em>worker</em> dédié puis le résultat est renvoyé à la page et affiché.</p> + +<p>Cet exemple est assez simple mais permet d'introduire les concepts de base autour des <em>workers</em>. Nous verrons certains détails plus avancés dans la suite de cet article.</p> + +<h3 id="Détecter_la_possibilité_dutiliser_les_workers">Détecter la possibilité d'utiliser les <em>workers</em></h3> + +<p>Afin de gérer une meilleure amélioration progressive, une rétro-compatibilité et de présenter des messages d'erreur adéquats, il pourra être utile d'envelopper le code relatif au <em>worker</em> de la façon suivante (<a href="https://github.com/mdn/simple-web-worker/blob/gh-pages/main.js">main.js</a>) :</p> + +<pre class="brush: js">if (window.Worker) { + ... +}</pre> + +<h3 id="Initier_un_worker_dédié">Initier un <em>worker</em> dédié</h3> + +<p>La création d'un nouveau <em>worker</em> est assez simple. On appellera le constructeur {{domxref("Worker.Worker", "Worker()")}} en indiquant l'URI du script à exécuter dans le <em>thread</em> associé au <em>worker</em> (<a href="https://github.com/mdn/simple-web-worker/blob/gh-pages/main.js">main.js</a>) :</p> + +<div style="overflow: hidden;"> +<pre class="brush: js">var monWorker = new Worker('worker.js'); +</pre> +</div> + +<h3 id="Envoyer_des_messages_au_worker_et_y_réagir">Envoyer des messages au <em>worker</em> et y réagir</h3> + +<p>L'intérêt principal des <em>workers</em> repose sur l'échange de messages à l'aide de la méthode {{domxref("Worker.postMessage", "postMessage()")}} et grâce au gestionnaire d'évènement {{domxref("Worker.onmessage", "onmessage")}}. Lorsqu'on souhaite envoyer un message au <em>worker</em>, on enverra des messages de la façon suivante (<a href="https://github.com/mdn/simple-web-worker/blob/gh-pages/main.js">main.js</a>) :</p> + +<pre class="brush: js">premierNombre.onchange = function() { + monWorker.postMessage([premierNombre.value, deuxiemeNombre.value]); + console.log('Message envoyé au worker'); +} + +deuxiemeNombre.onchange = function() { + monWorker.postMessage([premierNombre.value, deuxiemeNombre.value]); + console.log('Message envoyé au worker'); +}</pre> + +<p>Ici, nous disposons de deux éléments {{htmlelement("input")}} représentés par les variables <code>premierNombre</code> et <code>deuxiemeNombre</code>. Lorsque l'un de ces deux champs est modifié, on utilise <code>monWorker.postMessage([premierNombre.value, deuxiemeNombre.value])</code> afin d'envoyer les deux valeurs au <em>worker</em> dans un tableau. Les messages peuvent être utilisés pour échanger n'importe quel type de valeur.</p> + +<p>Dans le <em>worker</em>, on peut réagir au message reçu grâce à un gestionnaire d'évènement comme celui-ci (<a href="https://github.com/mdn/simple-web-worker/blob/gh-pages/worker.js">worker.js</a>) :</p> + +<pre class="brush: js">onmessage = function(e) { + console.log('Message reçu depuis le script principal.'); + var workerResult = 'Résultat : ' + (e.data[0] * e.data[1]); + console.log('Envoi du message de retour au script principal'); + postMessage(workerResult); +}</pre> + +<p>Le gestionnaire <code>onmessage</code> permet d'exécuter du code lorsqu'un message est reçu. Le message même est disponible grâce à l'attribut <code>data</code> de l'évènement. Dans cet exemple, nous multiplions simplement les deux nombres avant d'utiliser <code>postMessage()</code> à nouveau afin d'envoyer le résultat via un message destiné au <em>thread</em> principal.</p> + +<p>De retour dans le <em>thread</em> principal, nous pouvons utiliser <code>onmessage</code> à nouveau pour réagir à la réponse provenant du <em>worker</em> :</p> + +<pre class="brush: js">monWorker.onmessage = function(e) { + resultat.textContent = e.data; + console.log('Message reçu depuis le worker'); +}</pre> + +<p>Ici, nous récupérons les données grâce à l'attribut <code>data</code> de l'évènement et nous mettons à jour le contenu du paragraphe avec l'attribut <code>textContent</code> de l'élément. Ainsi, l'utilisateur peut visualiser le résultat du calcul.</p> + +<div class="note"><strong>Note :</strong> On notera que <code>onmessage</code> et <code>postMessage()</code> doivent être rattachés à un objet <code>Worker</code> lorsqu'ils sont utilisés depuis le <em>thread</em> principal (ici, c'était <code>monWorker</code>) mais pas lorsqu'ils sont employés depuis le <em>worker</em>. En effet, dans le <em>worker</em>, c'est le <em>worker</em> qui constitue la portée globale et qui met à disposition ces méthodes.</div> + +<div class="note"><strong>Note :</strong> Lorsqu'un message est envoyé d'un <em>thread</em> à l'autre, ses données sont copiées. Elles ne sont pas partagées. Voir <a href="#échange">ci-après</a> pour plus d'explications à ce sujet.</div> + +<h3 id="Clôturer_un_worker">Clôturer un <em>worker</em></h3> + +<p>Si on doit arrêter un <em>worker</em> immédiatement, on pourra utiliser la méthode {{domxref("Worker", "terminate")}} depuis le <em>thread</em> principal :</p> + +<pre class="brush: js">monWorker.terminate();</pre> + +<p>Lorsque cette méthode exécuté, le <em>thread</em> associé au <em>worker</em> est tué immédiatement.</p> + +<h3 id="Gérer_les_erreurs">Gérer les erreurs</h3> + +<p>Lorsqu'une erreur d'exécution se produit avec le <em>worker</em>, son gestionnaire d'évènement <code>onerror</code> est appelé et reçoit un évènement <code>error</code> qui implémente l'interface <code>ErrorEvent</code>.</p> + +<p>Cet évènement ne bouillonne (<em>bubble</em>) pas et peut être annulé. Pour empêcher les conséquences par défaut, on pourra utiliser la méthode <a class="internal" href="/fr/docs/Web/API/Event/preventDefault"> <code>preventDefault()</code></a> rattachée à l'évènement d'erreur.</p> + +<p>L'évènement décrivant l'erreur possède notamment trois propriétés intéressantes :</p> + +<dl> + <dt><code>message</code></dt> + <dd>Un message d'erreur compréhensible par un humain.</dd> + <dt><code>filename</code></dt> + <dd>Le nom du fichier pour lequel l'erreur s'est produite.</dd> + <dt><code>lineno</code></dt> + <dd>Le numéro de ligne au sein du fichier responsable de l'erreur.</dd> +</dl> + +<h3 id="Initier_des_workers_fils">Initier des <em>workers</em> fils</h3> + +<p>Les <em>workers</em> peuvent également engendrer d'autres <em>workers</em>. Ces <em>workers</em>-fils doivent être hébergés sur la même origine que la page initiale. De plus, les URI des <em>workers-</em>fils sont résolues relativement à l'emplacement du <em>worker</em> père (plutôt que par rapport à la page parente). Ces contraintes permettent de simplifier le suivi des dépendances.</p> + +<h3 id="Importer_des_scripts_et_des_bibliothèques">Importer des scripts et des bibliothèques</h3> + +<p>Les <em>threads</em> d'exécution des <em>workers</em> peuvent accéder à la fonction globale <code>importScripts()</code>, qui leur permet d'importer des scripts. Cette fonction prend zéro à plusieurs URL en paramètres et importe les ressources associées. Voici quelques exemples valides :</p> + +<pre class="brush: js">importScripts(); /* n'importe rien */ +importScripts('toto.js'); /* importe uniquement "toto.js" */ +importScripts('toto.js', 'truc.js'); /* importe deux scripts */ +importScripts('//example.com/hello.js'); /* importe un script d'une autre origine */</pre> + +<p>Lors d'un import, le navigateur chargera chacun des scripts puis l'exécutera. Chaque script pourra ainsi mettre à disposition des objets globaux qui pourront être utilisés par le <em>worker</em>. Si le script ne peut pas être chargé, une exception <code>NETWORK_ERROR</code> sera levée et le code assicé ne sera pas exécuté. Le code exécuté précédemment (y compris celui-ci reporté à l'aide de {{domxref("window.setTimeout()")}}) continuera cependant d'être fonctionnel. Les déclarations de fonction situées <strong>après</strong> <code>importScripts()</code> sont également exécutées car évaluées avant le reste du code.</p> + +<div class="note"><strong>Note :</strong> Les scripts peuvent être téléchargés dans n'importe quel ordre mais ils seront exécutés dans l'ordre des arguments passés à <code>importScripts()</code> . Cet exécution est effectuée de façon synchrone et <code>importScripts()</code> ne rendra pas la main tant que l'ensemble des scripts n'auront pas été chargés et exécutés.</div> + +<h2 id="Les_workers_partagés">Les <em>workers</em> partagés</h2> + +<p>Un <em>worker</em> partagé est accessible par plusieurs scripts (même si ceux-ci proviennent de différentes fenêtres, <em>iframes</em> voire d'autres <em>workers</em>). Dans cette section, nous illustrerons les concepts à l'aide de <a href="https://github.com/mdn/simple-shared-worker">l'exemple simple d'un <em>worker</em> partagé.</a> Cet exemple est semblable à l'exemple utilisé pour le <em>worker</em> dédié. Il diffère car il possède deux fonctions, gérées par deux fichiers de script distincts : une fonction permettant de multiplier deux nombres et une fonction permettant d'élever un nombre au carré. Les deux scripts utilisent le même <em>worker</em> pour réaliser le calcul demandé.</p> + +<p>Ici, nous nous intéresserons particulièrement aux différences entre les <em>workers</em> dédiés et les <em>workers</em> partagés. Dans cet exemple, nous aurons deux pages HTML, chacune utilisant du code JavaScript employant le même <em>worker</em>.</p> + +<div class="note"> +<p><strong>Note :</strong> Si on peut accéder à un <em>worker</em> partagé depuis différents contextes de navigations, ces contextes de navigation doivent néanmoins partager la même origine (même protocole, même hôte, même port).</p> +</div> + +<div class="note"> +<p><strong>Note :</strong> Dans Firefox, les <em>workers</em> partagés ne peuvent pas être partagés entre les documents chargés en navigation privée et les documents chargés en navigation classique ({{bug(1177621)}}).</p> +</div> + +<h3 id="Initier_un_worker_partagé">Initier un <em>worker</em> partagé</h3> + +<p>La création d'un nouveau <em>worker</em> partagé est assez semblable à la création d'un <em>worker</em> dédié. On utilise alors un constructeur différent :</p> + +<pre class="brush: js">var monWorker = new SharedWorker('worker.js');</pre> + +<p>Une différence fondamentale avec les <em>workers</em> dédiés est l'utilisation d'un objet <code>port</code> pour la communication. Un port sera explicitement ouvert pour être utilisé afin de communiquer avec le <em>worker</em> (dans le cas des <em>workers</em> dédiés, ce port est ouvert implicitement).</p> + +<p>La connexion au port doit être démarrée implicitement avec l'utilisation du gestionnaire d'évènement <code>onmessage</code> ou explicitement avec la méthode <code>start()</code> avant qu'un message soit envoyé. On utilisera uniquement <code>start()</code> si l'évènement <code>message</code> est détecté avec la méthode <code>addEventListener()</code>.</p> + +<div class="note"> +<p><strong>Note :</strong> Lorsqu'on utilise la méthode <code>start()</code> afin d'ouvrir le port de connexion, celle-ci doit être appelée de part et d'autre (depuis le <em>thread</em> parent <strong>et</strong> depuis le <em>worker</em>) si on souhaite disposer d'une connexion bidirectionnelle.</p> +</div> + +<h3 id="Échanger_des_messages_avec_un_worker_partagé_et_y_réagir">Échanger des messages avec un <em>worker</em> partagé et y réagir</h3> + +<p>On peut alors envoyer des messages au <em>worker</em>. Dans le cas d'un <em>worker</em> partagé, la méthode <code>postMessage()</code> doit être appelée via l'objet <code>port</code> (là aussi, vous pouvez étudier le code de <a href="https://github.com/mdn/simple-shared-worker/blob/gh-pages/multiply.js">multiply.js</a> et <a href="https://github.com/mdn/simple-shared-worker/blob/gh-pages/square.js">square.js</a>) :</p> + +<pre class="brush: js">carreNombre.onchange = function() { + monWorker.port.postMessage([carreNombre.value, carreNombre.value]); + console.log('Message envoyé au worker'); +}</pre> + +<p>Du côté du <em>worker</em>, les choses sont également légèrement plus compliquées (voir <a href="https://github.com/mdn/simple-shared-worker/blob/gh-pages/worker.js">worker.js</a>) :</p> + +<pre class="brush: js">onconnect = function(e) { + var port = e.ports[0]; + + port.onmessage = function(e) { + var workerResult = 'Résultat : ' + (e.data[0] * e.data[1]); + port.postMessage(workerResult); + } +}</pre> + +<p>On commence par utiliser le gestionnaire <code>onconnect</code> afin de déclencher du code à la connexion au port (c'est-à-dire lorsque le gestionnaire <code>onmessage</code> est déclaré depuis le <em>thread</em> parent ou lorsque la méthode <code>start()</code> est invoquée explicitement depuis le <em>thread</em> parent).</p> + +<p>On utilise l'attribut <code>ports</code> de l'évènement afin de récupérer le port utilisé et on le place dans une variable.</p> + +<p>Ensuite, sur ce port, on ajoute un gestionnaire d'évènement pour l'évènement <code>message</code> afin de faire les calculs et de renvoyer le résultat au <em>thread</em> principal. En définissant ce gestionnaire pour <code>message</code> dans le <em>thread</em> du <em>worker</em>, on ouvre implicitement le port pour la connexion au <em>thread</em> parent : il n'est donc pas nécessaire d'invoquer <code>port.start()</code>.</p> + +<p>Enfin, dans le script de la page, on gère le message du résultat (voir <a href="https://github.com/mdn/simple-shared-worker/blob/gh-pages/multiply.js">multiply.js</a> et <a href="https://github.com/mdn/simple-shared-worker/blob/gh-pages/square.js">square.js</a>):</p> + +<pre class="brush: js">monWorker.port.onmessage = function(e) { + result2.textContent = e.data; + console.log('Message reçu depuis le worker'); +}</pre> + +<p>Lorsqu'un message provient du port associé au <em>worker</em>, on vérifie son type puis on insère le résultat dans le paragraphe associé.</p> + +<h2 id="Sûreté_des_threads">Sûreté des <em>threads</em></h2> + +<p>L'interface {{domxref("Worker")}} engendre des <em>threads</em> au sens du système d'exploitation. Certains développeurs avertis pourront se demander si cette communication à base de <em>threads</em> ne peut pas générer d'effets indésirables tels que des situations de compétition (<em>race conditions</em>).</p> + +<p>Toutefois, la communication entre les <em>web workers</em> est contrôlée explicitement dans les scripts et il n'y a pas d'accès aux composants ou au DOM qui ne seraient pas sûrs à ce niveau. De plus, la communication entre les <em>threads</em> s'effectue par recopie de données. Aussi, s'il n'est théoriquement pas impossible de ne pas avoir de tels problèmes, il faudrait les chercher pour les provoquer.</p> + +<h2 id="Règles_de_sécurité_du_contenu_content_security_policy_CSP">Règles de sécurité du contenu (<em>content security policy</em>, CSP)</h2> + +<p>Les <em>workers</em> disposent de leur propre contexte d'exécution, distinct de celui du document qui les a créés. Aussi, en général, les <em>workers</em> ne sont pas gérés par la <a href="/fr/docs/Web/HTTP/CSP">politique de sécurité de contenu</a> du document (ou du <em>worker</em> parent) responsable de leur création. Ainsi, si un document est servi avec l'en-tête suivant :</p> + +<pre>Content-Security-Policy: script-src 'self'</pre> + +<div>Cette règle empêchera n'importe quel script inclus dans le document d'utiliser <code><a href="/fr/docs/Web/JavaScript/Reference/Objets_globaux/eval">eval()</a></code>. Toutefois, si le script génère un <em>worker</em>, le code exécuté par ce <em>worker</em> pourra utiliser <code>eval()</code>.<br> +<br> +Pour appliquer une règle de sécurité au <em>worker</em>, il faudra fournir un en-tête <a href="/fr/docs/Web/HTTP/Headers/Content-Security-Policy">Content-Security-Policy</a> approprié pour la requête responsable du service du script du <em>worker</em>.<br> +<br> +Si l'origine du script du <em>worker</em> est un identifiant global unique (si son URL utilise le schéma <code>data://</code> ou <code>blob://</code> par exemple), le <em>worker</em> héritera du CSP associé au document responsable de sa création.</div> + +<div></div> + +<h2 id="Échanger_des_données_avec_les_workers_plus_de_détails"><a id="échange" name="échange">Échanger des données avec les <em>workers</em> : plus de détails</a></h2> + +<p>Les données échangées entre le document principal et les <em>workers</em> sont <strong>copiées</strong> et non partagées. Lorsqu'ils sont envoyés au <em>worker</em>, les objets sont sérialisés (puis désérialisés à leur réception). La page et le <em>worker</em> <strong>ne partagent pas le même exemplaire </strong>et on a donc deux versions d'une part et d'autre. La plupart des navigateurs implémentent cette approche avec <a href="/fr/docs/Web/API/Web_Workers_API/algorithme_clonage_structure">une clonage structurel</a>.</p> + +<p>Pour illustrer ce point, on prendra une fonction intitulée <code>emulateMessage()</code> et qui simule le comportement d'une valeur clonée (pas partagée) avec un <em>worker</em> attaché à la page principale et réciproquement :</p> + +<pre class="brush: js">function emulateMessage(vVal) { + return eval('(' + JSON.stringify(vVal) + ')'); +} + +// Tests + +// test #1 +var example1 = new Number(3); +console.log(typeof example1); // object +console.log(typeof emulateMessage(example1)); // number + +// test #2 +var example2 = true; +console.log(typeof example2); // boolean +console.log(typeof emulateMessage(example2)); // boolean + +// test #3 +var example3 = new String('Hello World'); +console.log(typeof example3); // object +console.log(typeof emulateMessage(example3)); // string + +// test #4 +var example4 = { + 'name': 'John Smith', + "age": 43 +}; +console.log(typeof example4); // object +console.log(typeof emulateMessage(example4)); // object + +// test #5 +function Animal(sType, nAge) { + this.type = sType; + this.age = nAge; +} +var example5 = new Animal('Cat', 3); +console.log(example5.constructor); // Animal +console.log(emulateMessage(example5).constructor); // Object</pre> + +<p>Une valeur qui est clonée et non partagée est appelée un message. Les messages peuvent être envoyés et reçus grâce à <code>postMessage()</code> et au gestionnaire d'évènement pour <code>message</code> (dont l'attribut {{domxref("MessageEvent.data", "data")}} contiendra les données copiées).</p> + +<p><strong>example.html</strong> (page principale) :</p> + +<pre class="brush: js">var myWorker = new Worker('my_task.js'); + +myWorker.onmessage = function(oEvent) { + console.log('Worker said : ' + oEvent.data); +}; + +myWorker.postMessage('ali');</pre> + +<p><strong>my_task.js</strong> (le code du <em>worker</em>) :</p> + +<pre class="brush: js">postMessage("I\'m working before postMessage(\'ali\')."); + +onmessage = function(oEvent) { + postMessage('Hi ' + oEvent.data); +};</pre> + +<p>L'<a href="/fr/docs/Web/API/Web_Workers_API/algorithme_clonage_structure">algorithme de clonage structurel</a> permet de sérialiser aussi bien des données JSON que d'autres formats et permet notamment de gérer les références circulaires (ce que JSON ne permet pas de gérer nativement).</p> + +<h3 id="Les_objets_transférables_-_échanger_des_données_avec_transfert_de_la_propriété">Les objets transférables - échanger des données avec transfert de la propriété</h3> + +<p>Chrome 17+ et Firefox 18+ permettent également d'échanger certains types d'objet (qualifiés de transférables et qui implémentent l'interface {{domxref("Transferable")}}) avec des <em>workers</em> et à haute performance. Les objets transférables sont passés d'un contexte à l'autre avec une opération <em><a href="https://en.wikipedia.org/wiki/Zero-copy">zero-copy</a> </em>qui permet d'obtenir des améliorations sensibles lors de l'échange de données volumineuses. On peut voir cela comme un passage de référence du monde C/C++ mais les données qui sont transférées depuis le contexte appelant ne sont plus disponibles dans ce contexte après le transfert. La propriété des données est transférée au nouveau contexte. Ainsi, lorsqu'on transfère un objet {{domxref("ArrayBuffer")}} depuis l'application principale vers le <em>worker</em>, l'objet {{domxref("ArrayBuffer")}} de départ est nettoyé et ne peut plus être utilisé, son contenu est (littéralement) transféré au contexte du <em>worker</em>.</p> + +<pre class="brush: js">// Créer un fichier de 32MB et le remplir. +var uInt8Array = new Uint8Array(1024 * 1024 * 32); // 32MB +for (var i = 0; i < uInt8Array.length; ++i) { + uInt8Array[i] = i; +} + +worker.postMessage(uInt8Array.buffer, [uInt8Array.buffer]); +</pre> + +<div class="note"> +<p><strong>Note :</strong> Pour plus d'informations quant aux objets transférables, aux performances associées et à la détection de ces fonctionnalités, on pourra lire <a href="https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast">Transferable Objects: Lightning Fast</a>.</p> +</div> + +<h2 id="Workers_embarqués"><em>Workers</em> embarqués</h2> + +<p>Il n'existe pas de méthode standard pour embarquer le code d'un worker dans une page web à la façon des éléments {{HTMLElement("script")}}. Toutefois, un élément {{HTMLElement("script")}}, qui ne possède pas d'attribut <code>src</code>, qui possède un attribut <code>type</code> ne correspondant pas à un type MIME exécutable pourra être considéré comme un bloc de données pouvant être utilisé par JavaScript. Ces blocs de données sont une fonctionnalité HTML5 qui permet de transporter n'importe quelle donnée textuelle. On pourrait donc embarquer un <em>worker</em> de cette façon :</p> + +<pre class="brush: html"><!DOCTYPE html> +<html> +<head> +<meta charset="UTF-8" /> +<title>Exemple MDN - Worker embarqué</title> +<script type="text/js-worker"> + // Ce script ne sera pas analysé par le moteur JS car + // son type MIME est text/js-worker. + var maVar = 'Coucou monde !'; + // Reste du code du worker. +</script> +<script type="text/javascript"> + // Ce script sera analysé par le moteur JS car son type MIME + // est text/javascript. + function pageLog(sMsg) { + // On utilise un fragment afin que le navigateur ne rende/peigne + // qu'une seule fois. + var oFragm = document.createDocumentFragment(); + oFragm.appendChild(document.createTextNode(sMsg)); + oFragm.appendChild(document.createElement('br')); + document.querySelector('#logDisplay').appendChild(oFragm); + } +</script> +<script type="text/js-worker"> + // Ce script ne sera pas analysé par le moteur JS car son type + // MIME est text/js-worker. + onmessage = function(oEvent) { + postMessage(myVar); + }; + // Reste du code du worker +</script> +<script type="text/javascript"> + // Ce script sera analysé par le moteur JS car son type MIME est + // text/javascript + + var blob = new Blob(Array.prototype.map.call(document.querySelectorAll('script[type=\'text\/js-worker\']'), function (oScript) { return oScript.textContent; }),{type: 'text/javascript'}); + + // On crée une nouvelle propriété document.worker qui contient + // tous les scripts "text/js-worker". + document.worker = new Worker(window.URL.createObjectURL(blob)); + + document.worker.onmessage = function(oEvent) { + pageLog('Received: ' + oEvent.data); + }; + + // On démarre le worker. + window.onload = function() { document.worker.postMessage(''); }; +</script> +</head> +<body><div id="logDisplay"></div></body> +</html></pre> + +<p>Le <em>worker</em> embarqué est désormais injecté dans la propriété <code>document.worker</code>.</p> + +<p>On notera également qu'on peut convertir une fonction en un <code>Blob</code> et générer une URL d'objet vers ce blob. Par exemple :</p> + +<pre class="brush: js">function fn2workerURL(fn) { + var blob = new Blob(['('+fn.toString()+')()'], {type: 'application/javascript'}) + return URL.createObjectURL(blob) +}</pre> + +<h2 id="Autres_exemples">Autres exemples</h2> + +<p>Dans cette section nous voyons d'autres exemples d'application.</p> + +<h3 id="Effectuer_des_calculs_en_arrière-plan">Effectuer des calculs en arrière-plan</h3> + +<p>Les <em>workers</em> sont notamment utiles pour réaliser des opérations de traitement intensives sans bloquer pour autant le <em>thread</em> responsable de l'interface utilisateur. Dans cet exemple, on utilise un<em> </em><em>worker</em> afin de calculer la suite de Fibonacci.</p> + +<h4 id="JavaScript">JavaScript</h4> + +<p>Le code JavaScript suivant sera enregistré dans le fichier "fibonacci.js" auquel on fera référence dans le document HTML ci-après.</p> + +<pre class="brush: js">var results = []; + +function resultReceiver(event) { + results.push(parseInt(event.data)); + if (results.length == 2) { + postMessage(results[0] + results[1]); + } +} + +function errorReceiver(event) { + throw event.data; +} + +onmessage = function(event) { + var n = parseInt(event.data); + + if (n == 0 || n == 1) { + postMessage(n); + return; + } + + for (var i = 1; i <= 2; i++) { + var worker = new Worker('fibonacci.js'); + worker.onmessage = resultReceiver; + worker.onerror = errorReceiver; + worker.postMessage(n - i); + } + };</pre> + +<p>On a défini la propriété <code>onmessage</code> avec une fonction qui recevra les messages envoyés au <em>worker</em> via <code>postMessage()</code>. On initie alors la récursion et on déclenche des copies du <em>worker</em> afin de gérer chacune des itérations liées au calcul.</p> + +<h4 id="HTML">HTML</h4> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="UTF-8" /> + <title>Test threads fibonacci</title> + </head> + <body> + + <div id="result"></div> + + <script language="javascript"> + + var worker = new Worker('fibonacci.js'); + + worker.onmessage = function(event) { + document.getElementById('result').textContent = event.data; + dump('Got: ' + event.data + '\n'); + }; + + worker.onerror = function(error) { + console.error('Worker error: ' + error.message + '\n'); + throw error; + }; + + worker.postMessage('5'); + + </script> + </body> +</html> +</pre> + +<p>Dans la page web, on crée un élément <code>div</code> avec l'identifiant <code>result</code>. C'est cet élément qui sera utilisé afin d'afficher le résultat.</p> + +<p>Ensuite, on lance le <em>worker</em>. Après avoir initié le <em>worker</em>, on configure le gestionnaire d'évènement <code>onmessage</code> afin d'afficher le résultat via le <code>div</code>. On configure également le gestionnaire <code>onerror</code> afin d'afficher l'erreur de la console.</p> + +<p>Enfin, on envoie un message au <em>worker</em> afin de le démarrer.</p> + +<p><a href="https://mdn.github.io/fibonacci-worker/">Essayer cet exemple</a>.</p> + +<h3 id="Répartir_des_tâches_entre_plusieurs_workers">Répartir des tâches entre plusieurs <em>workers</em></h3> + +<p>Les ordinateurs dotés de plusieurs coeurs se généralisent et il peut s'avérer utile de fragmenter une tâche complexe entre différents <em>workers</em> afin de tirer parti des différents coeurs du processeur.</p> + +<h2 id="Autres_workers">Autres <em>workers</em></h2> + +<p>En plus des web <em>workers</em> (dédiés et partagés), il existe d'autres types de <em>workers </em>:</p> + +<ul> + <li><a href="/en-US/docs/Web/API/ServiceWorker_API">Les service <em>workers</em></a> peuvent notamment servir de serveurs mandataires (<em>proxy</em>) entre les applications web, le navigateur et le réseau (lorsque celui-ci est disponible). Ces <em>workers</em> sont conçus afin de permettre des utilisations hors-ligne en interceptant les requêtes réseau et en déclenchant les actions nécessaires selon que le réseau est disponible ou non et que les ressources souhaitées sont disponibles sur le serveur. Ces <em>workers</em> permettent de déclencher des notifications <em>push</em> et d'utiliser des API de synchronisation en arrière-plan.</li> + <li><a href="/fr/docs/Web/API/Web_Audio_API#Audio_processing_in_JavaScript">Les <em>worklets </em>audio</a> permettent de traiter des signaux audios en arrière-plan (fonctionnalité expérimentale).</li> +</ul> + +<h2 id="Fonctions_et_interfaces_disponibles_pour_les_workers">Fonctions et interfaces disponibles pour les <em>workers</em></h2> + +<p>La plupart des fonctionnalités JavaScript standard peuvent être utilisées dans les <em>web workers</em>, dont :</p> + +<ul> + <li>{{domxref("Navigator")}}</li> + <li>{{domxref("XMLHttpRequest")}}</li> + <li>{{jsxref("Objets_globaux/Array", "Array")}}, {{jsxref("Objets_globaux/Date", "Date")}}, {{jsxref("Objets_globaux/Math", "Math")}} et {{jsxref("Objets_globaux/String", "String")}}</li> + <li>{{domxref("WindowTimers.setTimeout")}} et {{domxref("WindowTimers.setInterval")}}</li> +</ul> + +<p>En revanche, un <em>worker</em> ne pourra pas directement manipuler la page parente et notamment le DOM et les objets de la page. Il faudra effectuer ce traitement indirectement, via des messages.</p> + +<div class="note"> +<p><strong>Note :</strong> Pour avoir une liste exhaustive des fonctionnalités disponibles pour les <em>workers</em>, voir <a href="/fr/docs/Web/API/Worker/Functions_and_classes_available_to_workers">les fonctions et interfaces disponibles pour les <em>workers</em></a>.</p> +</div> + +<h2 id="Spécifications">Spécifications</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">Spécification</th> + <th scope="col">État</th> + <th scope="col">Commentaires</th> + </tr> + <tr> + <td>{{SpecName('HTML WHATWG', '#workers', 'Web workers')}}</td> + <td>{{Spec2('HTML WHATWG')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="Compatibilité_des_navigateurs">Compatibilité des navigateurs</h2> + +<div>{{CompatibilityTable}}</div> + +<div id="compat-desktop"> +<table class="compat-table"> + <tbody> + <tr> + <th>Fonctionnalité</th> + <th>Chrome</th> + <th>Firefox (Gecko)</th> + <th>Internet Explorer</th> + <th>Opera</th> + <th>Safari (WebKit)</th> + </tr> + <tr> + <td>Support simple</td> + <td>4<sup>[1]</sup></td> + <td>{{CompatGeckoDesktop("1.9.1")}}</td> + <td>10.0</td> + <td>10.6<sup>[1]</sup></td> + <td>4<sup>[2][5]</sup></td> + </tr> + <tr> + <td><em>Workers</em> partagés</td> + <td>4<sup>[1]</sup></td> + <td>{{CompatGeckoDesktop(29)}}</td> + <td>{{CompatNo}}</td> + <td>10.6</td> + <td>5<br> + {{CompatNo}} 6.1<sup>[4]</sup></td> + </tr> + <tr> + <td>Echange de données via le clonage structuré</td> + <td>13</td> + <td>{{CompatGeckoDesktop(8)}}</td> + <td>10.0</td> + <td>11.5</td> + <td>6</td> + </tr> + <tr> + <td>Echange de données via les objets transférables</td> + <td>17 {{property_prefix("webkit")}}<br> + 21</td> + <td>{{CompatGeckoDesktop(18)}}</td> + <td>{{CompatNo}}</td> + <td>15</td> + <td>6</td> + </tr> + <tr> + <td>Variable globale {{domxref("window.URL", "URL")}}</td> + <td>10<sup>[3]</sup><br> + 23</td> + <td>{{CompatGeckoDesktop(21)}}</td> + <td>11</td> + <td>15</td> + <td>6<sup>[3]</sup></td> + </tr> + </tbody> +</table> +</div> + +<div id="compat-mobile"> +<table class="compat-table"> + <tbody> + <tr> + <th>Fonctionnalité</th> + <th>Android</th> + <th>Chrome pour Android</th> + <th>Firefox Mobile (Gecko)</th> + <th>Firefox OS (Gecko)</th> + <th>IE Phone</th> + <th>Opera Mobile</th> + <th>Safari Mobile</th> + </tr> + <tr> + <td>Support simple</td> + <td>4.4</td> + <td>4<sup>[1]</sup></td> + <td>3.5</td> + <td>1.0.1</td> + <td>10.0</td> + <td>11.5<sup>[1]</sup></td> + <td>5.1<sup>[2][5]</sup></td> + </tr> + <tr> + <td>Shared workers</td> + <td>{{CompatNo}}</td> + <td>4<sup>[1]</sup></td> + <td>8</td> + <td>1.0.1</td> + <td>{{CompatNo}}</td> + <td>{{CompatNo}}</td> + <td>{{CompatNo}}</td> + </tr> + <tr> + <td>Echange de données via le clonage structuré</td> + <td>{{CompatNo}}</td> + <td>4</td> + <td>8</td> + <td>1.0.1</td> + <td>{{CompatNo}}</td> + <td>{{CompatNo}}</td> + <td>{{CompatNo}}</td> + </tr> + <tr> + <td>Echange de données via les objets transférables</td> + <td>{{CompatNo}}</td> + <td>{{CompatNo}}</td> + <td>18</td> + <td>1.0.1</td> + <td>{{CompatNo}}</td> + <td>{{CompatNo}}</td> + <td>{{CompatNo}}</td> + </tr> + </tbody> +</table> +</div> + +<p>[1] Chrome et Opera provoquent une erreur "<code>Uncaught SecurityError: Failed to construct 'Worker': Script at 'file:///Path/to/worker.js' cannot be accessed from origin 'null'.</code>" lorsqu'on souhaite accéder au <em>worker</em> en local. Il faut un domaine <em>réel</em> pour le faire.</p> + +<p>[2] Avec Safari 7.1.2, on peut appeler <code>console.log</code> depuis un <em>worker</em> mais cela n'affichera rien dans la console. Les versions antérieures ne permettent pas d'appeler <code>console.log</code> depuis un <em>worker</em>.</p> + +<p>[3] Cette fonctionnalité est préfixée : <code>webkitURL</code>.</p> + +<p>[4] Safari a <a href="https://bugs.webkit.org/show_bug.cgi?id=116359">retiré la prise en charge de SharedWorker</a>.</p> + +<p>[5] Avec Safari v.12+ (iOS & MacOS), les <em>web workers</em> sont uniquement démarrés après une interaction utilisateur (un clic par exemple). Les <em>workers</em> pourront être créés mais ne seront pas exécutés tant qu'ils n'y aura pas eu d'interaction.</p> + +<h2 id="Voir_aussi">Voir aussi</h2> + +<ul> + <li><a href="/fr/docs/Web/API/Worker">L'interface <code>Worker</code></a></li> + <li><a href="/fr/docs/Web/API/SharedWorker">L'interface <code>SharedWorker</code></a></li> + <li><a href="/fr/docs/Web/API/Worker/Functions_and_classes_available_to_workers">Les fonctions disponibles dans les <em>workers</em></a></li> +</ul> |