关于 Web Workers 你需要了解的 7 件事
当前位置:以往代写 > 网页教程 >关于 Web Workers 你需要了解的 7 件事
2019-06-14

关于 Web Workers 你需要了解的 7 件事

关于 Web Workers 你需要了解的 7 件事

  WebWorkers是HTML5提供的一个Javascript多线程解决方案,它允许你在后台运行JavaScript代码,而不会阻止web用户界面。WebWorkers可以提高网页的整体性能,还可以增强用户体验。WebWorkers有两种风格——专用WebWorkers和共享WebWorkers。本文讨论了你所需要知道的Webworker的七个关键方面,帮助你决定在应用程序中使用它们的话。

WebWorkers

  1.WebWorkers允许你在后台运行JavaScript代码

  通常,你在Web页面中编写的JavaScript代码在与用户界面相同的线程中执行。这就是为什么当你点击一个会触发漫长处理过程的按钮,网页的用户界面会冻结。除非处理完成,否则你就无法工作于用户界面。Webworker允许你在后台执行JavaScript,以便用户界面保持响应,即使同时正在执行某些脚本。执行脚本的后台线程通常称为workerthread或worker。你可以生成尽可能多的worker,只要你想。你还可以将数据传递到正在workerthread中执行的脚本,并在完成时将值返回到主线程。然而,WebWorkers有一些限制,如下所示:

  WebWorkers无法从web页面访问DOM元素。

  WebWorkers无法从web页面访问全局变量和JavaScript函数。

  WebWorkers不能调用alert()或confirm()函数。

  不能在WebWorkers中访问诸如窗口,文档和parent这样的对象。

  但是,你可以使用setTimeout(),setInterval()等函数。你也可以使用XMLHttpRequest对象向服务器发出Ajax请求。

  2.WebWorkers有两种类型

  WebWorkers有两种类型:专用WebWorkers和共享WebWorkers。专用WebWorkers随同创建它们的网页一起存在和死亡。这意味着在网页中创建的专用WebWorkers无法通过多个网页访问。另一方面,共享WebWorkers在多个网页之间是共享的。Worker类代表专用WebWorkers,而SharedWorker类代表共享WebWorkers。

  在许多情况下,专用WebWorkers就可以满足你的需求。这是因为通常你需要在workerthread中执行一个网页的特定脚本。然而,有时,你需要在workerthread中执行一个脚本,并且这个workerthread对多个网页通用。在这种情况下,创建许多专用WebWorkers,每个页面一个,还不如使用共享WebWorkers。由一个网页创建的共享webworker仍然可用于其他网页。只有当所有到它的连接被关闭,才能毁坏它。共享WebWorkers比专用WebWorkers更复杂一点。

  3.Worker对象代表专用WebWorker

  现在,你了解了WebWorkers的基础知识,让我们看看如何使用专用WebWorkers。下面讨论的示例假设你已使用喜欢的开发工具创建了一个Web应用程序,并且还在其Script文件夹中添加了jQuery和Modernizr库。将HTML页面添加到web应用程序,然后键入以下代码:

 3.Worker对象代表专用WebWorker    现在,你了解了WebWorkers的基础知识,让我们看看如何使用专用WebWorkers。下面讨论的示例假设你已使用喜欢的开发工具创建了一个Web应用程序,并且还在其Script文件夹中添加了jQuery和Modernizr库。将HTML页面添加到web应用程序,然后键入以下代码:

  上面的HTML页面包含一个触发一些JavaScript处理的按钮(btnStart)。请注意,该网页引用了Modernizr和jQuery库。<script>块包括ready()方法处理程序,并且该处理程序又反过来处理btnStart的单击事件。ready()处理程序首先检查浏览器是否支持webworkers。这通过使用Modernizr的webworkers属性完成。如果浏览器不支持Webworkers,则会向用户显示一条错误消息。

  然后代码连接btnStart的点击事件处理程序。点击事件处理程序的代码很重要,因为它使用Worker对象在后台运行脚本。点击事件处理程序创建一个Worker对象并将其存储在本地变量——worker中。要在后台执行的JavaScript文件的路径在构造函数中传递。你将很快创建LengthyTask.js。然后,代码为Worker对象的消息事件添加一个事件处理程序。当目标脚本(在此情况下为LengthyTask.js)将一些值发送回网页时,会引发消息事件。消息事件处理函数可以使用evt.data属性来访问返回的值。最后,在Worker对象上调用postMessage()方法来触发LengthyTask.js的执行。postMessage()方法还允许你将数据传递到目标脚本。在此示例中,将一个数字(10000)传递给postMessage(),postMessage()指示处理应持续的毫秒数量。你可以传递postMessage()调用中的任何其他数据,如JavaScript对象或字符串。

  LengthyTask.js文件包含要在后台执行的代码,如下所示:

#p#分页标题#e#

然后代码连接btnStart的点击事件处理程序。点击事件处理程序的代码很重要,因为它使用Worker对象在后台运行脚本。点击事件处理程序创建一个Worker对象并将其存储在本地变量——worker中。要在后台执行的JavaScript文件的路径在构造函数中传递。你将很快创建LengthyTask.js。然后,代码为Worker对象的消息事件添加一个事件处理程序。当目标脚本(在此情况下为LengthyTask.js)将一些值发送回网页时,会引发消息事件。消息事件处理函数可以使用evt.data属性来访问返回的值。最后,在Worker对象上调用postMessage()方法来触发LengthyTask.js的执行。postMessage()方法还允许你将数据传递到目标脚本。在此示例中,将一个数字(10000)传递给postMessage(),postMessage()指示处理应持续的毫秒数量。你可以传递postMessage()调用中的任何其他数据,如JavaScript对象或字符串。    LengthyTask.js文件包含要在后台执行的代码,如下所示:

  上面的代码处理workerthread的消息事件。当主页面调用Worker对象上的postMessage()方法时,会引发消息事件。消息事件处理程序通过运行某些毫秒的do-while循环来模拟冗长的处理。此循环运行的毫秒数从主页传递(回忆前面讨论的postMessage())。因此,evt.data在此示例中返回10000。一旦长时间操作完成,代码调用postMessage()会把处理结果发送回主页面。在本例中,传递currentDate的值(currentDate是一个Date对象)。

  如果你运行主网页并单击StartProcessing按钮,那么你将在10秒后收到alert()。同时,页面的用户界面不会被阻止,你可以执行诸如滚动,点击等操作,表明来自LengthyTask.js的代码正在后台运行。

  4.SharedWorker对象代表共享WebWorker

  前面的示例使用了专用Webworker。让我们将同样的示例转换为使用共享Webworker。共享Webworker由SharedWorker对象表示。下面的代码显示了来自主页的代码的修改版本:

  4.SharedWorker对象代表共享WebWorker    前面的示例使用了专用Webworker。让我们将同样的示例转换为使用共享Webworker。共享Webworker由SharedWorker对象表示。下面的代码显示了来自主页的代码的修改版本:

  注意用粗体字标记的代码。它创建了一个SharedWorker实例,并在构造函数中传递SharedLengthyTask.js。你将很快创建此文件。然后,代码将消息事件处理程序连接到SharedWorker对象的端口对象。消息处理程序函数执行与前面示例中相同的工作。然后代码在端口对象上调用start()方法。最后,在端口对象上调用postMessage()方法将数据(10000)发送到共享workerthread。

  SharedLengthyTask.js文件包含以下代码:

注意用粗体字标记的代码。它创建了一个SharedWorker实例,并在构造函数中传递SharedLengthyTask.js。你将很快创建此文件。然后,代码将消息事件处理程序连接到SharedWorker对象的端口对象。消息处理程序函数执行与前面示例中相同的工作。然后代码在端口对象上调用start()方法。最后,在端口对象上调用postMessage()方法将数据(10000)发送到共享workerthread。    SharedLengthyTask.js文件包含以下代码:

  代码首先声明一个名为port的变量,用于存储端口对象的引用。这次处理了两个事件——connect和message。当与共享Webworker建立连接时,会触发connect事件。connect事件处理程序捕获evt.port[0]对象并将其存储在之前声明的端口变量中。然后在端口对象上连接消息事件处理程序。调用端口对象的start()方法来开始侦听该端口上的消息。消息事件处理程序几乎与你在前面的示例中编写的消息事件处理程序相同,除了它附加到端口对象这一点。此外,在端口对象上调用postMessage(),以将处理结果发送到主页面。

  5.WebWorkers可以使用XMLHttpRequest与服务器通信

  有时WebWorker可能需要与Web服务器通信。例如,你可能需要驻留在某些RDBMS中的数据以便于客户端处理。要完成此类任务,你可以使用XMLHttpRequest对象向服务器端资源发出请求。实例化Worker对象和处理消息事件的整个过程保持不变。但是,你需要向服务器端资源发出GET或POST请求。考虑下面的代码:

#p#分页标题#e#

有时WebWorker可能需要与Web服务器通信。例如,你可能需要驻留在某些RDBMS中的数据以便于客户端处理。要完成此类任务,你可以使用XMLHttpRequest对象向服务器端资源发出请求。实例化Worker对象和处理消息事件的整个过程保持不变。但是,你需要向服务器端资源发出GET或POST请求。考虑下面的代码:

  上面显示的代码创建了XMLHttpRequest对象的实例。然后调用open()方法,并指定向服务器端资源LengthyTaskHandler.ashx(一个ASP.NET通用处理程序)发出GET请求。(虽然此示例使用ASP.NET通用处理程序,但你可以使用任何其他服务器端资源。)然后它处理XMLHttpRequest对象的load事件并调用postMessage()。xhr.responseText作为postMessage()的参数。xhr.responseText将是ASP.NET通用处理程序作为响应返回的值。请求完成时引发load事件。

  LengthyTaskHandler.ashx包含以下代码:

 上面显示的代码创建了XMLHttpRequest对象的实例。然后调用open()方法,并指定向服务器端资源LengthyTaskHandler.ashx(一个ASP.NET通用处理程序)发出GET请求。(虽然此示例使用ASP.NET通用处理程序,但你可以使用任何其他服务器端资源。)然后它处理XMLHttpRequest对象的load事件并调用postMessage()。xhr.responseText作为postMessage()的参数。xhr.responseText将是ASP.NET通用处理程序作为响应返回的值。请求完成时引发load事件。    LengthyTaskHandler.ashx包含以下代码:

  正如你可以看到,ProcessRequest()通过在Thread类上调用Sleep()方法来模拟一些冗长的处理,并阻止执行10秒。然后它返回一个成功消息“Processingsuccessful!”给调用者。如果你在进行这些更改后运行主网页,你会发现在10秒后,将显示一个包含此成功消息的警报对话框。

  6.你可以使用错误事件捕获未处理的错误

  如果你的Webworker正在进行一些复杂的操作,那么你可能需要添加错误处理到主网页代码,以便在worker中出现任何未处理错误时,可以采取适当的操作。这可以通过处理Worker对象的错误事件来完成。每当workthread中存在任何未处理的错误时,就会抛出错误事件。以下代码显示了如何完成此操作:

 6.你可以使用错误事件捕获未处理的错误    如果你的Webworker正在进行一些复杂的操作,那么你可能需要添加错误处理到主网页代码,以便在worker中出现任何未处理错误时,可以采取适当的操作。这可以通过处理Worker对象的错误事件来完成。每当workthread中存在任何未处理的错误时,就会抛出错误事件。以下代码显示了如何完成此操作:

  从上面的代码可以看出,错误处理程序已经连接到worker对象的错误事件。错误处理函数接收一个事件对象,而该对象提供错误信息,例如发生错误的行号(evt.lineno),错误消息(evt.message)和发生错误的文件(evt.filename)。

  7.你可以使用Terminate()方法终止worker

  有时你可能会想要取消worker中正在执行的任务。对此,你可以通过调用其terminate()方法来摧毁Worker。一旦Worker终止,你就不能重新使用或重新启动它。当然,你总是可以创建另一个Worker实例并使用它。但请记住,terminate()会立即杀死了worker,并且不会给你任何机执行清理操作。

  看完七个关键方面,小编还是要着重提醒大家:

  1、WebWorker的创建是在主线程当中通过传入文件的url来实现的。如下所示:

  varwebworker=newWorker('my_task.js');

  返回的webworker对象,该对象可以完成与worker线程的通信,主要通过webworker.postMessage()向线程发送消息,通过webworker.onmessage=function(evt){}来监听worker线程发送到主线程的消息,通过webworker.onerror=function(evt){}来监听线程中的错误消息,通过webworker.terminate()来告诉worker线程立即终止执行。

  2、webworker线程是无法操作Dom对象的,所以像prompt、alert、console等都是无法在webworker线程中使用的,所以调试不太处理。但是可以将调试发送给主线程,主线程通过webworker线程发出的请求作出处理。

  3、用于创建webworker线程的js文件必须和当前页面遵循同源策略,也就是说不能跨域请求js文件;另外,线程之间的消息传递是不能有Function对象的,就是说不能够传递函数,在safari浏览器中只能传递数字/字符串等基本值(连Object都不行)。并且所有线程之间的数据并不是常规的引用方式,都是一份独立的拷贝。因此一般情况下,我们会将传递的参数转化为字符串进行传递,可以通过JSON.stringify()和JSON.parse()来处理。

  下面是一个简单的例子:

#p#分页标题#e#

3、用于创建webworker线程的js文件必须和当前页面遵循同源策略,也就是说不能跨域请求js文件;另外,线程之间的消息传递是不能有Function对象的,就是说不能够传递函数,在safari浏览器中只能传递数字/字符串等基本值(连Object都不行)。并且所有线程之间的数据并不是常规的引用方式,都是一份独立的拷贝。因此一般情况下,我们会将传递的参数转化为字符串进行传递,可以通过JSON.stringify()和JSON.parse()来处理。    下面是一个简单的例子:

3、用于创建webworker线程的js文件必须和当前页面遵循同源策略,也就是说不能跨域请求js文件;另外,线程之间的消息传递是不能有Function对象的,就是说不能够传递函数,在safari浏览器中只能传递数字/字符串等基本值(连Object都不行)。并且所有线程之间的数据并不是常规的引用方式,都是一份独立的拷贝。因此一般情况下,我们会将传递的参数转化为字符串进行传递,可以通过JSON.stringify()和JSON.parse()来处理。    下面是一个简单的例子:

  同源的webworker线程my_task.js:

同源的webworker线程my_task.js:

  效果展示:

效果展示

  这个地方有一个需要注意的就是,用来测试的js和html文件都需要发布到站点才可以正常访问,否则会提示这个错误:

这个地方有一个需要注意的就是,用来测试的js和html文件都需要发布到站点才可以正常访问,否则会提示这个错误:

  小编一般是用iis配一个测试站点。

  小编结语:

  Webworkers允许你在后台执行脚本而不冻结网页用户界面。有两种类型——专用webworker和共享webworker。每个网页创建专用webworker,而跨多个网页使用共享webworker共享。Worker类代表专用webworker,SharedWorker类代表共享webworker。本文介绍了如何使用这两种类型,文中还讨论了如何处理错误以及webworker如何使用XMLHttpRequest与web服务器通信。

    关键字:

在线提交作业