WebWorker 工作线程

来源:互联网 发布:战斗妖精雪风小说淘宝 编辑:程序博客网 时间:2024/06/05 22:58

WebWorker H5工作线程

1、多线程的支持
2、三大主要特征:能够长时间运行、理想的启动性能、理想的内存消耗
3、允许在 Web 程序中并发执行多个 JavaScript 脚本,每个脚本执行流都称为一个线程,彼此间互相独立,并且有浏览器中的 JavaScript 引擎负责管理

工作线程与多线程编程

1、HTML5 中的 Web Worker 可以分为两种不同线程类型,一个是专用线程 Dedicated Worker,一个是共享线程 Shared Worker

专用线程:Dedicated Worker

1、创建线程:

在创建专用线程的时候,需要给 Worker 的构造函数提供一个指向 JavaScript 文件资源的 URL,这也是创建专用线程时 Worker 构造函数所需要的唯一参数。
示例代码:var worker = new Worker(‘dedicated.js’);

2、与一个专用线程通信

专用线程在运行的过程中会在后台使用 MessagePort 对象,而 MessagePort 对象支持 HTML5 中多线程提供的所有功能,例如:可以发送和接受结构化数据(JSON 等),传输二进制数据,并且支持在不同端口中传输数据等。
为了在页面主程序接收从专用线程传递过来的消息,我们需要使用工作线程的 onmessage 事件处理器
示例代码:worker.onmessage = function (event) { … };
向专用线程发数据:用postmessage方法

共享线程:Shared Worker

1、共享线程

定义方式:一、通过指向JavaScript脚本资源的URL来创建、二、通过显示的名称

2、共享线程的创建

创建共享线程可以通过使用 SharedWorker() 构造函数来实现,这个构造函数使用 URL 作为第一个参数,即是指向 JavaScript 资源文件的 URL,同时,如果开发人员提供了第二个构造参数,那么这个参数将被用于作为这个共享线程的名称。
示例代码:var worker = new SharedWorker(‘sharedworker.js’, ’ mysharedworker ’ );

3、与共享线程通信

共享线程的通信也是跟专用线程一样,是通过使用隐式的 MessagePort 对象实例来完成的。当使用 SharedWorker() 构造函数的时候,这个对象将通过一种引用的方式被返回回来。我们可以通过这个引用的 port 端口属性来与它进行通信。
发送消息与接收消息的代码:

// 从端口接收数据 , 包括文本数据以及结构化数据1. worker.port.onmessage = function (event) { define your logic here... }; // 向端口发送普通文本数据2. worker.port.postMessage('put your message here … '); // 向端口发送结构化数据3. worker.port.postMessage({ username: 'usertext'; live_city: ['data-one', 'data-two', 'data-three','data-four']});

第一个我们使用 onmessage 事件处理器来接收消息,第二个使用 postMessage 来发送普通文本数据,第三个使用 postMessage 来发送结构化的数据,这里使用了 JSON 数据格式

工作线程事件处理模型

当工作线程被一个具有 URL 参数的构造函数创建的时候,它需要有一系列的处理流程来处理和记录它本身的数据和状态。
工作线程的处理模型如下:
1. 创建一个独立的并行处理环境,并且在这个环境里面异步的运行下面的步骤。
2. 如果它的全局作用域是 SharedWorkerGlobalScope 对象,那么把最合适的应用程序缓存和它联系在一起。
3. 尝试从它提供的 URL 里面使用 synchronous 标志和 force same-origin 标志获取脚本资源。
4. 新脚本创建的时候会按照下面的步骤:
创建这个脚本的执行环境。
使用脚本的执行环境解析脚本资源。
设置脚本的全局变量为工作线程全局变量。
设置脚本编码为 UTF-8 编码。
5. 启动线程监视器,关闭孤儿线程。
6. 对于挂起线程,启动线程监视器监视挂起线程的状态,即时在并行环境中更改它们的状态。
7. 跳入脚本初始点,并且启动运行。
8. 如果其全局变量为 DedicatedWorkerGlobalScope 对象,然后在线程的隐式端口中启用端口消息队列。
9. 对于事件循环,等待一直到事件循环列表中出现新的任务。
10. 首先运行事件循环列表中的最先进入的任务,但是用户代理可以选择运行任何一个任务。
11. 如果事件循环列表拥有存储 mutex 互斥信号量,那么释放它。
12. 当运行完一个任务后,从事件循环列表中删除它。
13. 如果事件循环列表中还有任务,那么继续前面的步骤执行这些任务。
14. 如果活动超时后,清空工作线程的全局作用域列表。
15. 释放工作线程的端口列表中的所有端口。

工作线程API

类库和脚本的访问和引入

对于类库和脚本的访问和引入,规范中规定可以使用 WorkerGlobalScope 对象的 importScripts(urls) 方法来引入网络中的脚本资源。

当用户调用这个方法引入资源的时候会执行下面的步骤来完成这个操作:
1. 如果没有给 importScripts 方法任何参数,那么立即返回,终止下面的步骤。
2. 解析 importScripts 方法的每一个参数。
3. 如果有任何失败或者错误,抛出 SYNTAX_ERR 异常。
4. 尝试从用户提供的 URL 资源位置处获取脚本资源。
5. 对于 importScripts 方法的每一个参数,按照用户的提供顺序,获取脚本资源后继续进行其它操作。

工作导航器对象

在 HTML5 中, WorkerUtils 接口的 navigator 属性会返回一个工作导航器对象(WorkerNavigator),这个对象定义并且代表了用户代理(即 Web 客户端)的标识和状态。因此,用户和 Web 脚本开发人员可以在多线程开发过程中通过这个对象来取得或者确定用户的状态。

工作导航器对象(WorkerNavigator)

WorkerUtils 抽象接口的 navigator 属性会返回一个 WorkerNavigator 用户接口,用于用户代理的识别的状态标识。我们来看下 WorkerNavigator 接口的定义。

WorkerNavigator 接口定义

接口定义代码
interface WorkerNavigator {};
WorkerNavigator implements NavigatorID;
WorkerNavigator implements NavigatorOnLine;

工作线程(Web Worker)应用与实践

应用场景:使用工作线程做后台数值(算法)计算

工作线程最简单的应用就是用来做后台计算,而这种计算并不会中断前台用户的操作。下面我们提供了一个工作线程的代码片段,用来执行一个相对来说比较复杂的任务:计算两个非常大的数字的最小公倍数和最大公约数。

在这个例子中,我们在主页面中创建一个后台工作线程,并且向这个工作线程分配任务(即传递两个特别大的数字),当工作线程执行完这个任务时,便向主页面程序返回计算结果,而在这个过程中,主页面不需要等待这个耗时的操作,可以继续进行其它的行为或任务。

我们把这个应用场景分为两个主要部分,一个是主页面,可以包含主 JavaScript 应用入口,用户其它操作 UI 等。另外一个是后台工作线程脚本,即用来执行计算任务。

主程序页面代码:

<!DOCTYPE HTML> <html> <head> <title> Background Worker Application Example 1: Complicated Number Computation </title> </head> <body> <div> The least common multiple and greatest common divisor is: <p id="computation_results">please wait, computing … </p> </div>  <script>  var worker = new Worker('numberworker.js'); worker.postMessage("{first:347734080,second:3423744400}");   worker.onmessage = function (event) {  document.getElementById(' computation_result').textContent = event.data; };  </script></body> </html>

后台工作线程代码

/**  * This worker is used to calculate  * the least common multiple  * and the greatest common divisor  */  onmessage = function (event)  {  var first=event.data.first;  var second=event.data.second;  calculate(first,second);  };  /*  * calculate the least common multiple  * and the greatest common divisor  */  function calculate(first,second) {     //do the calculation work  var common_divisor=divisor(first,second);  var common_multiple=multiple(first,second);     postMessage("Work done! " + "The least common multiple is "+common_divisor  +" and the greatest common divisor is "+common_multiple);  }  /**  * calculate the greatest common divisor  * @param number  * @param number  * @return  */  function divisor(a, b) {  if (a % b == 0) {  return b;  } else {  return divisor(b, a % b);  }  }  /**  * calculate the least common multiple  * @param number  * @param number  * @return  */  function multiple( a,  b) {  var multiple = 0;  multiple = a * b / divisor(a, b);  return multiple;  }

在主程序页面中,我们使用 Worker()构造函数创建一个新的工作线程,它会返回一个代表此线程本身的线程对象。接下来我们使用这个线程对象与后台脚本进行通信。线程对象有两个主要事件处理器:postMessage 和 onmessage 。postMessage 用来向后台脚本发送消息,onmessage 用以接收从后台脚本中传递过来的消息。

在后台工作线程代码片段中,我们定一个两个 JavaScript 函数,一个是 function divisor:用以计算最大公约数,一个是 function multiple:用以计算最小公倍数。同时工作线程的 onmessage 事件处理器用以接收从主页面中传递过来的数值,然后把这两个数值传递到 function calculate 用以计算。当计算完成后,调用事件处理器 postMessage,把计算结果发送到主页面。

IN THE END

HTML5 Web Worker 的多线程特性为基于 Web 系统开发的程序人员提供了强大的并发程序设计功能,它允许开发人员设计开发出性能和交互更好的富客户端应用程序。本文不仅仅详细讲述 HTML5 中的多线程规范。同时,也以几种典型的应用场景为例,以实例的形式讲解 HTML5 中多线程编程以及应用,为用户提供了详细而全面的参考价值,并且指导开发人员设计和构建更为高效和稳定的 Web 多线程应用。

原创粉丝点击