Rumah  >  Artikel  >  hujung hadapan web  >  Mulakan dengan Pekerja Web

Mulakan dengan Pekerja Web

WBOY
WBOYasal
2023-09-04 12:49:011139semak imbas

Salah satu daripada banyak matlamat reka bentuk bahasa JavaScript adalah untuk kekal satu benang dan ringkas. Walaupun saya mesti mengakui, memandangkan sifat struktur bahasa, ia adalah sesuatu yang mudah! Tetapi apa yang kami maksudkan dengan "benang tunggal" ialah terdapat hanya satu rangkaian kawalan dalam JavaScript ya, malangnya, enjin JavaScript anda hanya boleh melakukan satu perkara pada satu masa.

Sekarang, bukankah ini kedengaran terlalu ketat untuk menggunakan pemproses berbilang teras terbiar pada komputer anda? HTML5 berjanji untuk mengubah semua itu.


Model benang tunggal untuk JavaScript

Pekerja Web hidup dalam dunia terhad tanpa akses kepada DOM kerana DOM tidak selamat untuk benang.

Sebuah aliran pemikiran melihat sifat JavaScript satu benang sebagai penyederhanaan, tetapi yang lain melihatnya sebagai pengehadan. Kumpulan yang kedua mempunyai perkara yang sangat baik, terutamanya kerana aplikasi web moden menggunakan JavaScript untuk mengendalikan acara UI, pertanyaan atau tinjauan pendapat bahagian pelayan API, memproses sejumlah besar data dan memanipulasi DOM berdasarkan respons pelayan. p>

Dapat melakukan begitu banyak operasi dalam satu rangkaian kawalan sambil mengekalkan UI responsif selalunya merupakan tugas yang sukar, memaksa pembangun untuk menggunakan penggodaman dan penyelesaian (seperti menggunakan setTimeout(), setInterval(), atau gunakan XMLHttpRequest dan acara DOM) untuk mencapai keselarasan. Walau bagaimanapun, perlu diingat bahawa teknologi ini sudah tentu menyediakan cara untuk membuat panggilan secara tidak segerak, tetapi tidak menyekat tidak semestinya bermakna serentak. John Resig menerangkan di blognya mengapa anda tidak boleh menjalankan apa-apa secara selari. setTimeout(), setInterval(),或者使用XMLHttpRequest和DOM事件)来实现并发。然而,值得注意的是,这些技术肯定提供了一种异步调用的方法,但非阻塞并不一定意味着并发。 John Resig 在他的博客上解释了为什么不能并行运行任何东西。

局限性

如果您使用 JavaScript 有相当长的时间,您很可能遇到过以下烦人的对话框,指出某些脚本执行时间过长。是的,几乎每次您的页面停止响应时,原因都可以归因于某些 JavaScript 代码。

从 Web Worker 开始

以下是浏览器在执行脚本时可能会挂起的一些原因:

  • 过多的 DOM 操作:DOM 操作可能是 JavaScript 中成本最高的操作。因此,大量 DOM 操作操作使您的脚本成为重构的良好候选者。
  • 永无休止的循环:扫描代码中是否存在复杂的嵌套循环永远不会有什么坏处。这些往往会做比实际需要的更多的工作。也许您可以找到提供相同功能的不同解决方案。
  • 将两者结合起来:当存在更优雅的解决方案(例如使用 DocumentFragment)时,我们能做的最糟糕的事情就是在循环中重复更新 DOM。

网络工作者来救援

...非阻塞并不一定意味着并发...

感谢 HTML5 和 Web Workers,您现在可以生成一个新线程——提供真正的异步。新工作线程可以在主线程处理 UI 事件时在后台运行,即使工作线程正忙于处理大量数据。例如,工作人员可以处理大型 JSON 结构以提取有价值的信息以在 UI 中显示。但我的废话已经够多了;让我们看看一些实际的代码。

创建工作人员

通常,与 Web Worker 相关的代码驻留在单独的 JavaScript 文件中。父线程通过在 Worker 构造函数中指定脚本文件的 URI 来创建一个新的 Worker,该 Worker 会异步加载并执行 JavaScript 文件。

var primeWorker = new Worker('prime.js');

启动一个工作线程

要启动一个工作线程,父线程会向该工作线程发送一条消息,如下所示:

var current = $('#prime').attr('value');
primeWorker.postMessage(current);

父页面可以使用 postMessage API 与工作人员通信,该 API 也用于跨源消息传递。除了向工作程序发送原始数据类型之外,postMessage API 还支持传递 JSON 结构。但是,您不能传递函数,因为它们可能包含对底层 DOM 的引用。

父线程和工作线程有自己独立的空间;来回传递的消息是复制的,而不是共享的。

在幕后,这些消息在工作线程处序列化,然后在接收端反序列化。因此,不鼓励向工作线程发送大量数据。

父线程还可以注册一个回调来侦听工作线程在执行其任务后发回的任何消息。这允许父线程在工作线程发挥作用后采取必要的操作(例如更新 DOM)。看看这段代码:

primeWorker.addEventListener('message', function(event){
    console.log('Receiving from Worker: '+event.data);
    $('#prime').html( event.data );
});

event 对象包含两个重要属性:

  • <b>target</b>:用于标识发送消息的worker;主要在多工作人员环境中有用。
  • <b>data</b>:worker 发送回其父线程的消息。

worker 本身包含在 prime.js 中,并注册从其父级接收的 message 事件。它还使用相同的 postMessage

Penghadan

Jika anda telah menggunakan JavaScript untuk apa-apa tempoh masa, kemungkinan besar anda telah menemui kotak dialog menjengkelkan berikut yang menyatakan bahawa skrip tertentu mengambil masa terlalu lama untuk dilaksanakan. Ya, hampir setiap kali halaman anda berhenti bertindak balas, puncanya boleh dikaitkan dengan beberapa kod JavaScript. 🎜 🎜Mulakan dengan Pekerja Web🎜 🎜Berikut ialah beberapa sebab penyemak imbas anda mungkin hang semasa melaksanakan skrip: 🎜
  • Operasi DOM yang berlebihan: Operasi DOM mungkin merupakan operasi yang paling mahal dalam JavaScript. Oleh itu, bilangan besar operasi manipulasi DOM menjadikan skrip anda calon yang baik untuk pemfaktoran semula.
  • Gelung Tidak Berakhir: Tidak rugi untuk mengimbas kod anda untuk mencari gelung bersarang yang kompleks. Ini cenderung melakukan lebih banyak kerja daripada yang sebenarnya diperlukan. Mungkin anda boleh mencari penyelesaian berbeza yang menyediakan fungsi yang sama.
  • Gabungkan kedua-duanya: Perkara paling buruk yang boleh kita lakukan ialah mengemas kini DOM secara berulang kali dalam gelung apabila penyelesaian yang lebih elegan wujud (seperti menggunakan DocumentFragment).
🎜 🎜Pekerja rangkaian datang untuk menyelamatkan🎜 🎜 🎜...tak sekat tak semestinya serentak...🎜 🎜 🎜Terima kasih kepada HTML5 dan Pekerja Web, anda kini boleh menghasilkan urutan baharu - menyediakan tak segerak yang sebenar. Urutan pekerja baharu boleh dijalankan di latar belakang sementara utas utama mengendalikan acara UI, walaupun utas pekerja sedang sibuk memproses sejumlah besar data. Sebagai contoh, pekerja boleh memproses struktur JSON yang besar untuk mengekstrak maklumat berharga untuk paparan dalam UI. Tetapi cukup dengan bertele-tele saya; mari kita lihat beberapa kod sebenar. 🎜

Cipta kakitangan

🎜Biasanya, kod yang berkaitan dengan Web Worker berada dalam fail JavaScript yang berasingan. Benang induk mencipta Worker baharu dengan menyatakan URI fail skrip dalam pembina Worker, yang memuatkan dan melaksanakan fail JavaScript secara tidak segerak. 🎜
self.addEventListener('message',  function(event){
    var currPrime = event.data, nextPrime;
    setInterval( function(){

    nextPrime = getNextPrime(currPrime);
    postMessage(nextPrime);	
    currPrime = nextPrime;

    }, 500);
});

Mulakan urutan pekerja

🎜Untuk memulakan urutan pekerja, utas induk menghantar mesej ke urutan pekerja seperti berikut: 🎜
self.close();
🎜Halaman induk boleh berkomunikasi dengan pekerja menggunakan API postMessage, yang juga digunakan untuk pemesejan silang asal. Selain menghantar jenis data primitif kepada pekerja, API postMessage juga menyokong struktur JSON yang lulus. Walau bagaimanapun, anda tidak boleh lulus fungsi kerana ia mungkin mengandungi rujukan kepada DOM asas. 🎜
🎜Urutan induk dan urutan pekerja mempunyai ruang bebasnya sendiri; 🎜🎜 🎜Di bawah tudung, mesej ini disiri pada urutan pekerja dan kemudian dinyahsiri di hujung penerima. Oleh itu, menghantar sejumlah besar data ke rangkaian pekerja adalah tidak digalakkan. 🎜 🎜Urutan induk juga boleh mendaftarkan panggilan balik untuk mendengar sebarang mesej yang dihantar semula oleh utas pekerja selepas melaksanakan tugasnya. Ini membolehkan urutan induk mengambil tindakan yang perlu (seperti mengemas kini DOM) selepas urutan pekerja telah melakukan tugasnya. Lihat kod ini: 🎜
primeWorker.terminate();
🎜event objek mengandungi dua sifat penting: 🎜
  • <b>sasaran</b>: digunakan untuk mengenal pasti pekerja yang menghantar mesej terutamanya berguna dalam persekitaran berbilang pekerja.
  • <b>data</b>: Mesej yang pekerja hantar semula ke urutan induknya.
🎜Pekerja itu sendiri terkandung dalam prime.js dan mendaftar untuk acara mesej yang diterima daripada induknya. Ia juga menggunakan API postMessage yang sama untuk berkomunikasi dengan urutan induk. 🎜
self.addEventListener('message',  function(event){
    var currPrime = event.data, nextPrime;
    setInterval( function(){

    nextPrime = getNextPrime(currPrime);
    postMessage(nextPrime);	
    currPrime = nextPrime;

    }, 500);
});

网络工作者生活在一个受限且线程安全的环境中。

在此示例中,我们只需找到下一个最大素数,然后重复将结果发送回父线程,父线程又用新值更新 UI。在工作者上下文中, selfthis 均指全局范围。 Worker 可以为 message 事件添加事件侦听器,也可以定义 onmessage 处理程序来侦听父线程发送的任何消息。

查找下一个素数的任务显然不是工作人员的理想用例,但在这里选择它是为了演示传递消息的概念。随后,我们确实探索了使用 Web Worker 真正能带来好处的可能且实际的用例。

终止员工

工人是资源密集型的;它们是操作系统级线程。因此,您不想创建大量工作线程,并且应该在 Web Worker 完成工作后终止它。工人可以终止自己,如下所示:

self.close();

或者父线程可以终止工作线程:

primeWorker.terminate();

安全和限制

在工作脚本中,我们无法访问许多重要的 JavaScript 对象,例如 documentwindowconsoleparent,最重要的是无法访问 DOM。没有 DOM 访问权限并且无法更新页面确实听起来限制太多,但这是一个重要的安全设计决策。想象一下,如果多个线程尝试更新同一元素,可能会造成严重破坏。因此,网络工作者生活在一个受限且线程安全的环境中。

话虽如此,您仍然可以使用worker来处理数据并将结果返回到主线程,然后主线程可以更新DOM。尽管他们被拒绝访问一些非常重要的 JavaScript 对象,但工作人员可以使用一些函数,例如 setTimeout()/clearTimeout()setInterval()/clearInterval()navigator 等。还可以在工作器内使用 XMLHttpRequestlocalStorage 对象。

同源限制

在工作者上下文中, selfthis 均指全局范围。

为了与服务器通信,工作人员必须遵循同源策略。例如,托管在 http://www.example.com/ 上的脚本无法访问 https://www.example.com/ 上的脚本。即使主机名相同,同源策略也规定协议也必须相同。通常,这不是问题。您很可能正在编写工作程序、客户端,并从同一域为它们提供服务,但了解限制总是有用的。

Google Chrome 的本地访问问题

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

但是,不建议在生产环境中使用此标志。因此,最好的选择是将这些文件托管在网络服务器上,并在任何支持的浏览器中测试您的网络工作人员。

调试 Worker 和错误处理

无法访问 console 使得这有点不简单,但是借助 Chrome 开发工具,人们可以像调试任何其他 JavaScript 代码一样调试工作代码。

从 Web Worker 开始

要处理 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 支持。

想象一下在单线程环境中与多线程相关的强大功能。可能性是无限的!

Atas ialah kandungan terperinci Mulakan dengan Pekerja Web. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn