Maison  >  Article  >  interface Web  >  Explication détaillée du multithread Javascript en HTML5

Explication détaillée du multithread Javascript en HTML5

黄舟
黄舟original
2017-03-25 16:10:252124parcourir

JavascriptMécanisme d'exécution
Avant HTML5, JavaScript dans le navigateur fonctionnait de manière monothread, bien qu'il existe de nombreuses façons d'implémenter une simulation multi-thread (par exemple : la méthode setinterval, la méthode setTimeout, etc.) en Javascript, mais l'exécution du programme est essentiellement toujours effectuée par le moteur JavaScript de manière monothread. . Le thread de travail introduit dans HTML5 permet au moteur Javascript côté navigateur d'exécuter du code Javascript simultanément, obtenant ainsi une bonne prise en charge de la programmation multithread côté navigateur - WebWorker

. Web Worker en HTML5 peut être divisé en deux types de threads différents, l'un est un thread dédié Dedicated Worker et l'autre est un thread partagé Shared Worker
Travailleur Web dédié Il peut communiquer avec d'autres travailleurs ou composants de navigateur,
mais il ne peut pas communiquer avec le DOM

Dédié signifie que ce fil ne gère qu'une seule exigence à la fois dans divers navigateurs grand public, à l'exception d'IE.

Créer un thread Créer un travailleur est très simple, il suffit de transmettre le nom du fichier JavaScript qui doit être exécuté dans le thread au constructeur

C'est tout .

Communication par thread
Pour communiquer entre le thread principal et le thread enfant, les méthodes postMessage et onmessage du thread
objet
sont utilisées. à qui ? L'expéditeur utilise la méthode postMessage et le destinataire utilise la méthode onmessage pour recevoir des données. PostMessage n'a qu'un seul paramètre, qui est les données transmises, et onmessage n'a également qu'un seul paramètre. S'il s'agit d'un événement, il est transmis. via l'événement.data obtient les données reçues

Envoyer

JSONdata
JSON est quelque chose de pris en charge nativement par JS. utilisé en vain. Utilisez JSON pour les données complexes. Par exemple :

Gestion des erreurs Lorsqu'une erreur se produit dans un thread, son rappel d'événement onerror sera appelé. La façon de gérer les erreurs est donc très simple : elle consiste à accrocher l'événement onerror de l'instance de thread. Cette fonction de rappel a un paramètre error, qui comporte 3 champs : message - le nom du fichier d'erreur ; le fichier de script où l'erreur s'est produite ;

Détruisez le fil
postMessage({'cmd': 'init', 'timestamp': Date.now()});

À l'intérieur du fil, utilisez la méthode close pour se détruire. Dans le thread principal en dehors du thread, utilisez la méthode terminate de l'instance de thread pour détruire le thread.
Code HTML :

Fichier de script code fibonacci.js :


Placez-les dans le même répertoire, exécutez le fichier d'échange et view Console, vous pouvez voir les résultats de l’opération.

Il y a un autre point ici. Dans le fil de discussion principal, l'événement onmessage peut être accroché d'une autre manière :

<script type="text/javascript">
  
onload
 = function(){
      var worker = 
new
 Worker(&#39;fibonacci.js&#39;);  
      worker.onmessage = function(event) {
        console.log("Result:" + event.data);
      };
      worker.onerror = function(error) {
        console.log("Error:" + error.message);
      };
      worker.postMessage(40);
  }  
  </script>
Personnellement, je pense que c'est très gênant, il est donc préférable d'utiliser directement onmessage. .


Utilisation d'autres fichiers de script
//fibonacci.js
var fibonacci = function(n) {
    
return
 n < 2 ? n : arguments.c
all
ee(n - 1) + arguments.callee(n - 2);
};
onmessage = function(event) {
    var n = parseInt(event.data, 10);
    postMessage(fibonacci(n));
};

Les threads de travail peuvent utiliser la méthode globale importScripts pour charger et utiliser d'autres fichiers de script de domaine ou
bibliothèques de classes

. Par exemple, les méthodes d'utilisation suivantes sont légales :
worker.addEvent
List
ener(&#39;message&#39;, function(event) {
   console.log("Result:" + event.data);
}, false);

Après l'importation, vous pouvez directement utiliser les méthodes de ces fichiers. Regardez un petit exemple sur Internet :


Certains internautes sur Internet ont également pensé à utiliser ici la méthode importScripts pour résoudre le problème du préchargement des ressources (le navigateur précharge la ressource sans analyser ni exécuter la ressource ). La raison est également très simple.
Imbrication de threads

importScripts();                        
importScripts(&#39;foo.js&#39;);                
importScripts(&#39;foo.js&#39;, &#39;bar.js&#39;);
Vous pouvez également créer des sous-threads dans le thread de travail, et les différentes opérations sont toujours les mêmes.

mportScripts(&#39;math_utilities.js&#39;); 
 
 onmessage = function (event) 
 { 
   var first = event.data.first; 
   var second = event.data.second; 
   calculate(first,second); 
 }; 
 
 function calculate(first,second) { 
    //do the calculation work 
   var common_divisor=divisor(first,second); 
   var common_multiple=multiple(first,second); 
   postMessage("Work done! " + 
      "The least common multiple is " + common_divisor  +
      " and the greatest common divisor is "+common_multiple); 
 }
Problèmes de synchronisation

Worker n'a pas de mécanisme de verrouillage et les problèmes de synchronisation multi-thread ne peuvent être résolus que par code (comme la définition de signaux

variables) .

共享型SharedWebWorker
  共享型web worker主要适用于多连接并发的问题。因为要处理多连接,所以它的API与专用型worker稍微有点区别。除了这一点,共享型web worker和专用型worker一样,不能访问DOM,并且对窗体属性的访问也受到限制。共享型web worker也不能跨越通信。
  页面脚本可以与共享型web worker通信,然而,与专用型web worker(使用了一个隐式的端口通信)稍微有点不同的是,通信是显式的通过使用一个端口(port)对象并附加上一个消息事件处理程序来进行的。

  在收到web worker脚本的首个消息之后,共享型web worker把一个事件处理程序附加到激活的端口上。一般情况下,处理程序会运行自己的postMessage()方法来把一个消息返回给调用代码,接着端口的start()方法生成一个有效的消息进程。
      看网上能找到的的唯一个例子:创建一个共享线程用于接收从不同连接发送过来的指令,然后实现自己的指令处理逻辑,指令处理完成后将结果返回到各个不同的连接用户。
HTML代码:

<script> 
  var worker = new SharedWorker(&#39;sharedworker.js&#39;); 
  var log = document.getElementByIdx_x_x_x_x(&#39;response_from_worker&#39;); 
  worker.port.addEventListener(&#39;message&#39;, function(e) { 
  //log the response data in web page 
  log.textContent =e.data; 
  }, false); 
  worker.port.start(); 
  worker.port.postMessage(&#39;ping from user web page..&#39;); 
  
  //following method will send user input to sharedworker 
  function postMessageToSharedWorker(input) 
  { 
  //define a json object to construct the request 
  var instructions={instruction:input.value}; 
  worker.port.postMessage(instructions); 
  } 
  </script>

 脚本文件代码:

 // 创建一个共享线程用于接收从不同连接发送过来的指令,指令处理完成后将结果返回到各个不同的连接用户。
 var connect_number = 0; 
 
 onconnect = function(e) { 
  connect_number =connect_number+ 1; 
  //get the first port here 
  var port = e.ports[0]; 
  port.postMessage(&#39;A new connection! The 
current
 connection number is &#39; 
  + connect_number); 
  port.onmessage = function(e) { 
   //get instructions from requester 
   var instruction=e.data.instruction; 
   var results=execute_instruction(instruction); 
    port.postMessage(&#39;Request: &#39;+instruction+&#39; Response &#39;+results 
      +&#39; from shared worker...&#39;); 
  }; 
 }; 
 function execute_instruction(instruction) 
 { 
 var result_value; 
 //implement your logic here 
 //execute the instruction... 
 return result_value;
 }

      在上面的共享线程例子中,在主页面即各个用户连接页面构造出一个共享线程对象,然后定义了一个方法 postMessageToSharedWorker 向共享线程发送来之用户的指令。同时,在共享线程的实现代码片段中定义 connect_number 用来记录连接到这个共享线程的总数。之后,用 onconnect 事件处理器接受来自不同用户的连接,解析它们传递过来的指令。最后,定义一个了方法 execute_instruction 用于执行用户的指令,指令执行完成后将结果返回给各个用户。

      这里我们并没有跟前面的例子一样使用到了工作线程的 onmessage 事件处理器,而是使用了另外一种方式 addEventListener。实际上,前面已经说过,这两种的实现原理基本一致,只是在这里有些稍微的差别,如果使用到了 addEventListener 来接受来自共享线程的消息,那么就要先使用 worker.port.start() 方法来启动这个端口。之后就可以像工作线程的使用方式一样正常的接收和发送消息

线程中能做的事
1.能使用setTimeout(), clearTimeout(), setInterval(),clearInterval()等函数。
2.能使用navigator对象。
3.能使用XMLHttpRequest来发送请求。
4.可以在线程中使用Web Storage。

5.线程中可以用self获取本线程的作用域。

线程中不能做的事
1.线程中是不能使用除navigator外的DOM/BOM对象,例如window,document(想要操作的话只能发送消息给worker创建者,通过回调函数操作)。
2.线程中不能使用主线程中的变量和函数。
3.线程中不能使用有"挂起"效果的操作命令,例如alert等。
4.线程中不能跨域加载JS。

线程也是需要消耗资源的,而且使用线程也会带来一定的复杂性,所以如果没有充足的理由来使用额外的线程的话,那么就不要用它。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn