Home > Article > Web Front-end > 7 Things to Know About Web Workers
Web Workers allow you to run JavaScript code in the background without blocking the web user interface. Web Workers can improve the overall performance of web pages and also enhance user experience. Web Workers come in two flavors - dedicated Web Workers and shared Web Workers. This article discusses seven key aspects of web workers that you need to know to help you decide to use them in your application.
Typically, the JavaScript code you write in a web page executes on the same thread as the user interface. That's why the web page's user interface freezes when you click a button that triggers a lengthy process. You can't work on the user interface until the processing is complete. Web workers allow you to execute JavaScript in the background so that the user interface remains responsive even if some scripts are executing at the same time. The background thread that executes the script is often called a worker thread or worker. You can spawn as many workers as you want. You can also pass data to a script that is executing in a worker thread and return the value to the main thread when completed. However, Web Workers have some limitations as follows:
Web Workers cannot access DOM elements from web pages.
Web Workers cannot access global variables and JavaScript functions from the web page.
Web Workers cannot call the alert() or confirm() functions.
Objects such as window, document and parent cannot be accessed in Web Workers.
However, you can use functions such as setTimeout() and setInterval(). You can also use the XMLHttpRequest object to make Ajax requests to the server.
There are two types of Web Workers: dedicated Web Workers and shared Web Workers. Dedicated Web Workers live and die along with the web pages that create them. This means that dedicated Web Workers created within a web page cannot be accessed across multiple web pages. Shared Web Workers, on the other hand, are shared across multiple web pages. The Worker class represents dedicated Web Workers, while the SharedWorker class represents shared Web Workers.
In many cases, dedicated Web Workers will meet your needs. This is because typically you need to execute specific scripts for a web page in a worker thread. However, sometimes, you need to execute a script in a worker thread that is common to multiple web pages. In this case, instead of creating many dedicated Web Workers, one for each page, you might as well use shared Web Workers. A shared web worker created by one web page can still be used by other web pages. It can only be destroyed if all connections to it are closed. Shared Web Workers are a bit more complicated than dedicated Web Workers.
Now that you understand the basics of Web Workers, let’s see how to use dedicated Web Workers. The examples discussed below assume that you have created a web application using your favorite development tools and also added the jQuery and Modernizr libraries in its Script folder. Add the HTML page to the web application and type the following code:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script src="scripts/modernizr.js"></script> <script src="scripts/jquery-2.0.0.js"></script> <script type="text/javascript"> $(document).ready(function () { if (!Modernizr.webworkers) { alert("This browser doesn't support Web Workers!"); return; } $("#btnStart").click(function () { var worker = new Worker("scripts/lengthytask.js"); worker.addEventListener("message", function (evt) { alert(evt.data); },false); worker.postMessage(10000); }); }); </script> </head> <body> <form> <input type="button" id="btnStart" value="Start Processing" /> </form> </body> </html>
The HTML page above contains a button (btnStart) that triggers some JavaScript processing. Please note that this page references the Modernizr and jQuery libraries. The 3f1c4e4b6b16bbbd69b2ee476dc4f83a block includes the ready() method handler, and this handler in turn handles btnStart's click event. The ready() handler first checks if the browser supports web workers. This is done using Modernizr’s webworkers property. If the browser does not support Web workers, an error message is displayed to the user.
Then the code connects to the click event handler of btnStart. The code for the click event handler is important because it uses a Worker object to run the script in the background. The click event handler creates a Worker object and stores it in a local variable - worker. The path to the JavaScript file to be executed in the background is passed in the constructor. You will create LengthyTask.js in no time. The code then adds an event handler for the Worker object's message event. The message event is raised when the target script (LengthyTask.js in this case) sends some value back to the web page. Message event handlers can use the evt.data property to access the returned value. Finally, the postMessage() method is called on the Worker object to trigger the execution of LengthyTask.js. The postMessage() method also allows you to pass data to the target script. In this example, a number (10000) is passed to postMessage(), which indicates the number of milliseconds that processing should last. You can pass any other data in the postMessage() call, such as JavaScript objects or strings.
The LengthyTask.js file contains the code to be executed in the background, as shown below:
addEventListener("message", function (evt) { var date = new Date(); var currentDate = null; do { currentDate = new Date(); } while (currentDate - date < evt.data); postMessage(currentDate); }, false);
上面的代码处理worker thread的消息事件。当主页面调用Worker对象上的postMessage()方法时,会引发消息事件。消息事件处理程序通过运行某些毫秒的do-while循环来模拟冗长的处理。此循环运行的毫秒数从主页传递(回忆前面讨论的postMessage())。因此,evt.data在此示例中返回10000。一旦长时间操作完成,代码调用postMessage()会把处理结果发送回主页面。在本例中,传递currentDate的值(currentDate是一个Date对象)。
如果你运行主网页并单击Start Processing按钮,那么你将在10秒后收到alert()。同时,页面的用户界面不会被阻止,你可以执行诸如滚动,点击等操作,表明来自LengthyTask.js的代码正在后台运行。
前面的示例使用了专用Web worker。让我们将同样的示例转换为使用共享Web worker。共享Web worker由SharedWorker对象表示。下面的代码显示了来自主页的代码的修改版本:
$(document).ready(function () { if (!Modernizr.webworkers) { alert("This browser doesn't support Web Workers!"); return; } $("#btnStart").click(function () { var worker = new SharedWorker("scripts/sharedlengthytask.js"); worker.port.addEventListener("message", function (evt) { alert(evt.data); }, false); worker.port.start(); worker.port.postMessage(10000); }); });
注意用粗体字标记的代码。它创建了一个SharedWorker实例,并在构造函数中传递SharedLengthyTask.js。你将很快创建此文件。然后,代码将消息事件处理程序连接到SharedWorker对象的端口对象。消息处理程序函数执行与前面示例中相同的工作。然后代码在端口对象上调用start()方法。最后,在端口对象上调用postMessage()方法将数据(10000)发送到共享worker thread。
SharedLengthyTask.js文件包含以下代码:
var port; addEventListener("connect", function (evt) { port = evt.ports[0]; port.addEventListener("message", function (evt) { var date = new Date(); var currentDate = null; do { currentDate = new Date(); } while (currentDate - date < evt.data); port.postMessage(currentDate); }, false); port.start(); }, false);
代码首先声明一个名为port的变量,用于存储端口对象的引用。这次处理了两个事件——connect和message。当与共享Web worker建立连接时,会触发connect事件。 connect事件处理程序捕获evt.port [0]对象并将其存储在之前声明的端口变量中。然后在端口对象上连接消息事件处理程序。调用端口对象的start()方法来开始侦听该端口上的消息。消息事件处理程序几乎与你在前面的示例中编写的消息事件处理程序相同,除了它附加到端口对象这一点。此外,在端口对象上调用postMessage(),以将处理结果发送到主页面。
有时Web Worker可能需要与Web服务器通信。例如,你可能需要驻留在某些RDBMS中的数据以便于客户端处理。要完成此类任务,你可以使用XMLHttpRequest对象向服务器端资源发出请求。实例化Worker对象和处理消息事件的整个过程保持不变。但是,你需要向服务器端资源发出GET或POST请求。考虑下面的代码:
addEventListener("message", function (evt) { var xhr = new XMLHttpRequest(); xhr.open("GET", "lengthytaskhandler.ashx"); xhr.onload = function () { postMessage(xhr.responseText); }; xhr.send(); }, false);
上面显示的代码创建了XMLHttpRequest对象的实例。然后调用open()方法,并指定向服务器端资源LengthyTaskHandler.ashx(一个ASP.NET通用处理程序)发出GET请求。(虽然此示例使用ASP.NET通用处理程序,但你可以使用任何其他服务器端资源。)然后它处理XMLHttpRequest对象的load事件并调用postMessage()。 xhr.responseText作为postMessage()的参数。xhr.responseText将是ASP.NET通用处理程序作为响应返回的值。请求完成时引发load事件。
LengthyTaskHandler.ashx包含以下代码:
namespace WebWorkersDemo { public class LengthyTaskHandler : IHttpHandler { public void ProcessRequest(HttpContext context) { System.Threading.Thread.Sleep(10000); context.Response.ContentType = "text/plain"; context.Response.Write("Processing successful!"); } public bool IsReusable { get { return false; } } } }
正如你可以看到,ProcessRequest()通过在Thread类上调用Sleep()方法来模拟一些冗长的处理,并阻止执行10秒。然后它返回一个成功消息“Processing successful!”给调用者。如果你在进行这些更改后运行主网页,你会发现在10秒后,将显示一个包含此成功消息的警报对话框。
如果你的Web worker正在进行一些复杂的操作,那么你可能需要添加错误处理到主网页代码,以便在worker中出现任何未处理错误时,可以采取适当的操作。这可以通过处理Worker对象的错误事件来完成。每当work thread中存在任何未处理的错误时,就会抛出错误事件。以下代码显示了如何完成此操作:
$("#btnStart").click(function () { var worker = new Worker("scripts/lengthytask.js"); worker.addEventListener("message", function (evt) { alert(evt.data); }, false); worker.addEventListener("error", function (evt) { alert("Line #" + evt.lineno + " - " + evt.message + " in " + evt.filename); }, false); worker.postMessage(10000); });
从上面的代码可以看出,错误处理程序已经连接到worker对象的错误事件。错误处理函数接收一个事件对象,而该对象提供错误信息,例如发生错误的行号(evt.lineno),错误消息(evt.message)和发生错误的文件(evt.filename)。
Sometimes you may want to cancel a task being executed in a worker. For this, you can destroy the Worker by calling its terminate() method. Once a Worker is terminated, you cannot reuse or restart it. Of course, you can always create another Worker instance and use it. But remember, terminate() kills the worker immediately and doesn't give you any chance to perform cleanup operations.
Web workers allow you to execute scripts in the background without freezing the web user interface. There are two types - dedicated web workers and shared web workers. Create a dedicated web worker for each web page, while use a shared web worker to share across multiple web pages. The Worker class represents a dedicated web worker and the SharedWorker class represents a shared web worker. This article explains how to use both types. It also discusses how errors are handled and how the webworker uses XMLHttpRequest to communicate with the web server.
The above is the detailed content of 7 Things to Know About Web Workers. For more information, please follow other related articles on the PHP Chinese website!