ホームページ >ウェブフロントエンド >jsチュートリアル >Web ワーカーから始める
JavaScript 言語の多くの設計目標の 1 つは、シングルスレッドでシンプルさを維持することでした。言語構造の性質を考えると、決して単純なものではないことは認めざるを得ません。ただし、「シングルスレッド」とは、JavaScript の制御スレッドが 1 つだけであることを意味します。残念ながら、JavaScript エンジンは一度に 1 つのことしか実行できません。
これでは、コンピュータ上のアイドル状態のマルチコア プロセッサを使用するには制限が多すぎるように思えませんか? HTML5 はそのすべてを変えることを約束します。
DOM はスレッドセーフではないため、Web ワーカーは DOM にアクセスできない制限された世界に住んでいます。
ある学派は JavaScript のシングルスレッドの性質を簡素化とみなしますが、別の学派はそれを制限とみなします。後者のグループには非常に良い点があり、特に最近の Web アプリケーションは UI イベントの処理、サーバー側 API のクエリまたはポーリング、大量のデータの処理、サーバー応答に基づく DOM の操作に JavaScript を多用しているためです。 p>
応答性の高い UI を維持しながら、制御の単一スレッドで非常に多くの操作を実行できるようにすることは、多くの場合困難な作業であり、開発者はハッキングや回避策 (setTimeout()
の使用など) に頼らざるを得ません。 ## setInterval()、または
XMLHttpRequest と DOM イベントを使用して) 同時実行を実現します。ただし、これらのテクノロジは確かに非同期呼び出しの方法を提供しますが、非ブロッキングは必ずしも同時実行を意味するわけではないことに注意してください。 John Resig は、並列実行できない理由を自身のブログで説明しています。
###制限###
スクリプトの実行時にブラウザがハングする理由は次のとおりです。
過剰な DOM 操作
スタッフを作成するHTML5 と Web Workers のおかげで、新しいスレッドを生成して真の非同期性を実現できるようになりました。新しいワーカー スレッドは、ワーカー スレッドが大量のデータの処理でビジーな場合でも、メイン スレッドが UI イベントを処理している間にバックグラウンドで実行できます。たとえば、ワーカーは大規模な JSON 構造を処理して、UI に表示する貴重な情報を抽出できます。とりとめのない話はこれくらいにして、実際のコードを見てみましょう。
通常、Web ワーカーに関連するコードは別の JavaScript ファイルに存在します。親スレッドは、
リーリー
ワーカースレッドを開始します
API を使用してワーカーと通信できます。
postMessage API は、プリミティブ データ型をワーカーに送信するだけでなく、JSON 構造の受け渡しもサポートしています。ただし、関数には基になる DOM への参照が含まれる可能性があるため、関数を渡すことはできません。
親スレッドとワーカー スレッドには独自の独立したスペースがあり、やり取りされるメッセージは共有されず、コピーされます。
これらのメッセージはバックグラウンドでワーカー スレッドでシリアル化され、受信側で逆シリアル化されます。したがって、ワーカー スレッドに大量のデータを送信することはお勧めできません。リーリー event親スレッドは、タスクの実行後にワーカー スレッドから送信されるメッセージをリッスンするコールバックを登録することもできます。これにより、ワーカー スレッドがジョブを完了した後に、親スレッドが必要なアクション (DOM の更新など) を実行できるようになります。このコードを見てください:
オブジェクトには 2 つの重要な属性が含まれています:
<b>
</b>
data
<b>
</b>ワーカー自体は
prime.js イベントに登録します。また、同じ postMessage
API を使用して親スレッドと通信します。
<pre class="brush:javascript;toolbal:false;">self.addEventListener('message', function(event){
var currPrime = event.data, nextPrime;
setInterval( function(){
nextPrime = getNextPrime(currPrime);
postMessage(nextPrime);
currPrime = nextPrime;
}, 500);
});
</pre>
<blockquote class="pullquote pqRight">
<p>网络工作者生活在一个受限且线程安全的环境中。</p>
</blockquote>
<p>在此示例中,我们只需找到下一个最大素数,然后重复将结果发送回父线程,父线程又用新值更新 UI。在工作者上下文中, <code>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 支持。
想象一下在单线程环境中与多线程相关的强大功能。可能性是无限的!
以上がWeb ワーカーから始めるの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。