L'un des nombreux objectifs de conception du langage JavaScript est de rester simple et monothread. Même si je dois l’admettre, compte tenu de la nature des structures linguistiques, c’est tout sauf simple ! Mais ce que nous entendons par « monothread », c'est qu'il n'y a qu'un seul thread de contrôle en JavaScript ; oui, malheureusement, votre moteur JavaScript ne peut faire qu'une seule chose à la fois.
Maintenant, cela ne semble-t-il pas trop restrictif pour utiliser le processeur multicœur inactif sur votre ordinateur ? HTML5 promet de changer tout cela.
Les Web Workers vivent dans un monde restreint sans accès au DOM car le DOM n'est pas thread-safe.
Une école de pensée considère la nature monothread de JavaScript comme une simplification, mais une autre y voit une limitation. Ce dernier groupe a un très bon point, d'autant plus que les applications Web modernes utilisent largement JavaScript pour gérer les événements de l'interface utilisateur, interroger ou interroger les API côté serveur, traiter de grandes quantités de données et manipuler le DOM en fonction des réponses du serveur. p>
Être capable d'effectuer autant d'opérations dans un seul thread de contrôle tout en conservant une interface utilisateur réactive est souvent une tâche difficile, obligeant les développeurs à recourir à des hacks et à des solutions de contournement (telles que l'utilisation de setTimeout()
, setInterval()
,或者使用XMLHttpRequest
et d'événements DOM) pour obtenir la simultanéité. Cependant, il convient de noter que ces technologies offrent certes un moyen d'appeler de manière asynchrone, mais que non bloquant ne signifie pas nécessairement simultané. John Resig explique sur son blog pourquoi on ne peut rien exécuter en parallèle.
Si vous utilisez JavaScript depuis un certain temps, vous avez probablement rencontré la boîte de dialogue ennuyeuse suivante indiquant que certains scripts prennent trop de temps à s'exécuter. Oui, presque chaque fois que votre page cesse de répondre, la cause peut être attribuée à du code JavaScript.
Voici quelques raisons pour lesquelles votre navigateur peut se bloquer lors de l'exécution de scripts :
...non bloquant ne signifie pas nécessairement simultané...
Grâce à HTML5 et Web Workers, vous pouvez désormais créer un nouveau fil de discussion, offrant une véritable asynchronie. Le nouveau thread de travail peut s'exécuter en arrière-plan pendant que le thread principal gère les événements de l'interface utilisateur, même si le thread de travail est occupé à traiter de grandes quantités de données. Par exemple, les employés peuvent traiter de grandes structures JSON pour extraire des informations précieuses à afficher dans l'interface utilisateur. Mais assez de mes divagations ; regardons du code réel.
En général, le code lié au Web Worker réside dans un fichier JavaScript distinct. Le thread parent crée un nouveau Worker en spécifiant l'URI du fichier de script dans le constructeur Worker
, qui charge et exécute le fichier JavaScript de manière asynchrone.
var primeWorker = new Worker('prime.js');
Pour démarrer un thread de travail, le thread parent envoie un message au thread de travail comme suit :
var current = $('#prime').attr('value'); primeWorker.postMessage(current);
La page parent peut utiliser postMessage
API 与工作人员通信,该 API 也用于跨源消息传递。除了向工作程序发送原始数据类型之外,postMessage
L'API prend également en charge la transmission de la structure JSON. Cependant, vous ne pouvez pas transmettre de fonctions car elles peuvent contenir des références au DOM sous-jacent.
Le fil parent et le fil de travail ont leur propre espace indépendant ; les messages échangés sont copiés et non partagés.
Sous le capot, ces messages sont sérialisés au niveau du thread de travail, puis désérialisés au niveau de la réception. Par conséquent, l’envoi de grandes quantités de données aux threads de travail est déconseillé.
Le thread parent peut également enregistrer un rappel pour écouter tous les messages renvoyés par le thread de travail après avoir effectué ses tâches. Cela permet au thread parent d'effectuer les actions nécessaires (telles que la mise à jour du DOM) une fois que le thread de travail a terminé son travail. Jetez un œil à ce code :
primeWorker.addEventListener('message', function(event){ console.log('Receiving from Worker: '+event.data); $('#prime').html( event.data ); });
event
L'objet contient deux propriétés importantes :
<code><b>target</b>
target<b>data</b>
</li>data</ul>
: le message que le travailleur renvoie à son fil parent.
prime.js
中,并注册从其父级接收的 message
事件。它还使用相同的 postMessage
Le
self.addEventListener('message', function(event){ var currPrime = event.data, nextPrime; setInterval( function(){ nextPrime = getNextPrime(currPrime); postMessage(nextPrime); currPrime = nextPrime; }, 500); });
网络工作者生活在一个受限且线程安全的环境中。
在此示例中,我们只需找到下一个最大素数,然后重复将结果发送回父线程,父线程又用新值更新 UI。在工作者上下文中, self
和 this
均指全局范围。 Worker 可以为 message
事件添加事件侦听器,也可以定义 onmessage
处理程序来侦听父线程发送的任何消息。
查找下一个素数的任务显然不是工作人员的理想用例,但在这里选择它是为了演示传递消息的概念。随后,我们确实探索了使用 Web Worker 真正能带来好处的可能且实际的用例。
工人是资源密集型的;它们是操作系统级线程。因此,您不想创建大量工作线程,并且应该在 Web Worker 完成工作后终止它。工人可以终止自己,如下所示:
self.close();
或者父线程可以终止工作线程:
primeWorker.terminate();
在工作脚本中,我们无法访问许多重要的 JavaScript 对象,例如 document
、window
、console
、parent
,最重要的是无法访问 DOM。没有 DOM 访问权限并且无法更新页面确实听起来限制太多,但这是一个重要的安全设计决策。想象一下,如果多个线程尝试更新同一元素,可能会造成严重破坏。因此,网络工作者生活在一个受限且线程安全的环境中。
话虽如此,您仍然可以使用worker来处理数据并将结果返回到主线程,然后主线程可以更新DOM。尽管他们被拒绝访问一些非常重要的 JavaScript 对象,但工作人员可以使用一些函数,例如 setTimeout()/clearTimeout()
、setInterval()/clearInterval()
、navigator
等。还可以在工作器内使用 XMLHttpRequest
和 localStorage
对象。
在工作者上下文中,
self
和this
均指全局范围。
为了与服务器通信,工作人员必须遵循同源策略。例如,托管在 http://www.example.com/
上的脚本无法访问 https://www.example.com/
上的脚本。即使主机名相同,同源策略也规定协议也必须相同。通常,这不是问题。您很可能正在编写工作程序、客户端,并从同一域为它们提供服务,但了解限制总是有用的。
Google Chrome 对本地访问工作程序设置了限制,因此您将无法在本地设置上运行这些示例。如果您想使用 Chrome,则必须在某个服务器上托管这些文件,或者在从命令行启动 Chrome 时使用 --allow-file-access-from-files
标志。对于 OS X,按如下方式启动 chrome:
$ /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --allow-file-access-from-files
但是,不建议在生产环境中使用此标志。因此,最好的选择是将这些文件托管在网络服务器上,并在任何支持的浏览器中测试您的网络工作人员。
无法访问 console
使得这有点不简单,但是借助 Chrome 开发工具,人们可以像调试任何其他 JavaScript 代码一样调试工作代码。
要处理 Web Worker 抛出的任何错误,您可以侦听 error
事件,该事件会填充 ErrorEvent 对象。您可以检查该对象以了解错误的详细原因。
primeWorker.addEventListener('error', function(error){ console.log(' Error Caused by worker: '+error.filename + ' at line number: '+error.lineno + ' Detailed Message: '+error.message); });
虽然多个工作线程在它们之间划分工作是很常见的,但需要注意的是。官方规范指定这些工作人员相对重量级,预计将是在后台运行的长期脚本。 Web Worker 不适合大量使用,因为它们的启动性能成本和每个实例的内存成本都很高。
该规范概述了两种类型的工作人员:专用工作人员和共享工作人员。到目前为止,我们已经看到了敬业工人的例子。它们直接链接到其创建者脚本/页面,因为它们与创建它们的脚本/页面具有一对一的关系。另一方面,共享工作人员可以在同一个来源的所有页面之间共享(即:同一来源的所有页面或脚本都可以与共享工作人员通信)。
要创建共享工作线程,只需将脚本的 URL 或工作线程的名称传递给 SharedWorker 构造函数即可。
共享工作程序使用方式的主要区别在于,它们与 port
相关联,以跟踪访问它们的父脚本。
以下代码片段创建一个共享工作线程,注册回调以监听该工作线程发布的任何消息,并将消息发布到共享工作线程:
var sharedWorker = new SharedWorker('findPrime.js'); sharedWorker.port.onmessage = function(event){ ... } sharedWorker.port.postMessage('data you want to send');
类似地,工作人员可以侦听 connect
事件,当新客户端尝试连接到工作人员时会收到该事件,然后相应地向其发送消息。
onconnect = function(event) { // event.source contains the reference to the client's port var clientPort = event.source; // listen for any messages send my this client clientPort.onmessage = function(event) { // event.data contains the message send by client var data = event.data; .... // Post Data after processing clientPort.postMessage('processed data'); } };
由于它们的共享性质,您可以在同一应用程序的不同选项卡中维护相同的状态,因为不同选项卡中的两个页面使用相同的共享工作脚本来维护和报告状态。有关共享工作人员的更多详细信息,我鼓励您阅读规范。
Web Worker 不适合大量使用,因为它们的启动性能成本很高,每个实例的内存成本也很高。
现实生活中的场景可能是,您被迫处理同步第三方 API,该 API 强制主线程在继续执行下一条语句之前等待结果。在这种情况下,您可以将此任务委托给新生成的工作线程,以利用异步功能为您带来好处。
Web 工作人员还擅长轮询情况,在这种情况下,您可以在后台连续轮询目标,并在一些新数据到达时将消息发布到主线程。
您可能还需要处理服务器返回的大量数据。传统上,处理大量数据会对应用程序的响应能力产生负面影响,从而使用户体验变得不可接受。更优雅的解决方案是将处理工作分配给多个工作人员来处理数据的非重叠部分。
其他用例可能是在多个网络工作人员的帮助下分析视频或音频源,每个工作人员都处理问题的预定义部分。
想象一下在单线程环境中与多个线程相关的强大功能。
与 HTML5 规范中的许多内容一样,Web Worker 规范也在不断发展。如果您打算成为网络工作者,那么看看规范不会有什么坏处。
对于使用当前版本的 Chrome、Safari 和 Firefox 的专业工作人员来说,跨浏览器支持相当不错。即使是 IE 也没有落后太多,IE10 占据了主导地位。但是,仅当前版本的 Chrome 和 Safari 支持共享工作线程。令人惊讶的是,Android 4.0 中提供的最新版本的 Android 浏览器不支持 Web Worker,尽管在 2.1 版本中支持了 Web Worker。 Apple 还从 iOS 5.0 开始提供了 Web Worker 支持。
想象一下在单线程环境中与多线程相关的强大功能。可能性是无限的!
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!