Web Workers允許你在背景執行JavaScript程式碼,而不會阻止web使用者介面。 Web Workers可以提升網頁的整體效能,還可以增強使用者體驗。 Web Workers有兩種風格-專用Web Workers和共用Web Workers。本文討論了你所需要知道的Web worker的七個關鍵方面,幫助你決定在應用程式中使用它們的話。
# 通常,你在Web頁面中編寫的JavaScript程式碼在與使用者介面相同的執行緒中執行。這就是為什麼當你點擊一個會觸發漫長處理過程的按鈕,網頁的使用者介面會凍結。除非處理完成,否則你就無法工作於使用者介面。 Web worker允許你在背景執行JavaScript,以便使用者介面保持回應,即使同時正在執行某些腳本。執行腳本的後台執行緒通常稱為worker thread或worker。你可以產生盡可能多的worker,只要你想。你也可以將資料傳遞到正在worker thread中執行的腳本,並在完成時將值傳回主執行緒。然而,Web Workers有一些限制,如下所示:
# Web Workers無法從web頁面存取DOM元素。
# Web Workers無法從web頁面存取全域變數和JavaScript函數。
# Web Workers不能呼叫alert()或confirm()函數。
# 不能在Web Workers中存取諸如窗口,文檔和parent這樣的物件。
但是,你可以使用setTimeout(),setInterval()等函數。你也可以使用XMLHttpRequest物件向伺服器發出Ajax請求。
Web Workers有兩種:專用Web Workers和共用Web Workers。專用Web Workers隨同創建它們的網頁一起存在和死亡。這意味著在網頁中建立的專用Web Workers無法透過多個網頁存取。另一方面,共用Web Workers在多個網頁之間是共用的。 Worker類別代表專用Web Workers,而SharedWorker類別代表共用Web Workers。
在許多情況下,專用Web Workers就可以滿足你的需求。這是因為通常你需要在worker thread中執行一個網頁的特定腳本。然而,有時,你需要在worker thread中執行一個腳本,而這個worker thread對多個網頁通用。在這種情況下,建立許多專用Web Workers,每個頁面一個,不如使用共用Web Workers。由一個網頁建立的共享web worker仍然可用於其他網頁。只有當所有到它的連接被關閉,才能毀壞它。共享Web Workers比專用Web Workers更複雜一點。
# 現在,你了解了Web Workers的基礎知識,讓我們來看看如何使用專用Web Workers。下面討論的範例假設你已使用喜歡的開發工具建立了一個Web應用程序,並且還在其Script資料夾中加入了jQuery和Modernizr函式庫。將HTML頁面新增至web應用程序,然後鍵入以下程式碼:
<!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>
上面的HTML頁麵包含一個觸發一些JavaScript處理的按鈕(btnStart)。請注意,該網頁引用了Modernizr和jQuery庫。 3f1c4e4b6b16bbbd69b2ee476dc4f83a區塊包含ready()方法處理程序,而處理程序又反過來處理btnStart的點擊事件。 ready()處理程序首先檢查瀏覽器是否支援web workers。這透過使用Modernizr的webworkers屬性完成。如果瀏覽器不支援Web workers,則會向使用者顯示錯誤訊息。
接著程式碼連接btnStart的點擊事件處理程序。點擊事件處理程序的程式碼很重要,因為它使用Worker物件在背景執行腳本。點擊事件處理程序建立一個Worker物件並將其儲存在本機變數——worker中。要在背景執行的JavaScript檔案的路徑在建構函式中傳遞。你將很快創建LengthyTask.js。然後,程式碼為Worker物件的消息事件新增一個事件處理程序。當目標腳本(在此情況下為LengthyTask.js)將一些值傳回網頁時,會引發訊息事件。訊息事件處理函數可以使用evt.data屬性來存取傳回的值。最後,在Worker物件上呼叫postMessage()方法來觸發LengthyTask.js的執行。 postMessage()方法也允許你將資料傳遞到目標腳本。在此範例中,將一個數字(10000)傳遞給postMessage(),postMessage()指示處理應持續的毫秒數。你可以傳遞postMessage()呼叫中的任何其他數據,如JavaScript物件或字串。
LengthyTask.js檔案包含要在背景執行的程式碼,如下所示:
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)。
# 有時你可能會想要取消worker中正在執行的任務。對此,你可以透過呼叫其terminate()方法來摧毀Worker。一旦Worker終止,你就不能重新使用或重新啟動它。當然,你總是可以創建另一個Worker實例並使用它。但請記住,terminate()會立即殺死了worker,並且不會給你任何機執行清理操作。
Web workers允許你在後台執行腳本而不凍結網頁使用者介面。有兩種類型-專用web worker和共享web worker。每個網頁創建專用web worker,而跨多個網頁使用共享web worker共享。 Worker類別代表專用web worker,SharedWorker類別代表共用web worker。本文介紹如何使用這兩種類型,文中也討論如何處理錯誤以及webworker如何使用XMLHttpRequest與web伺服器通訊。
以上是需要了解關於Web Workers的7件事的詳細內容。更多資訊請關注PHP中文網其他相關文章!