至 2008 年 W3C 制定出第一个 HTML5 草案开始,HTML5 承载了愈来愈多崭新的特性和功能。它不但强化了 Web 系统或网页的表现性能,并且还增长了对本地数据库等 Web 应用功能的支持。其中,最重要的一个即是对多线程的支持。在 HTML5 中提出了工做线程(Web Worker)的概念,而且规范出 Web Worker 的三大主要特征:可以长时间运行(响应),理想的启动性能以及理想的内存消耗。Web Worker 容许开发人员编写可以长时间运行而不被用户所中断的后台程序,去执行事务或者逻辑,并同时保证页面对用户的及时响应。本文深刻 HTML5 多线程规范,讲述多线程实现原理、方法,同时以实例的形式讲解 HTML5 中多线程编程以及应用。html
W3C 中的工做线程规范到目前为止已经定义了出了一系列公共接口,它容许 Web 程序开发人员去建立后台线程在他们的主页面中并发的运行脚本。这将使得线程级别的消息通讯成为现实。html5
传统上的线程能够解释为轻量级进程,它和进程同样拥有独立的执行控制,通常状况下由操做系统负责调度。而在 HTML5 中的多线程是这样一种机制,它容许在 Web 程序中并发执行多个 JavaScript 脚本,每一个脚本执行流都称为一个线程,彼此间互相独立,而且有浏览器中的 JavaScript 引擎负责管理。下面咱们将详细讲解 HTML5 的工做线程原理。web
在 HTML5 中,工做线程的出现使得在 Web 页面中进行多线程编程成为可能。众所周知,传统页面中(HTML5 以前)的 JavaScript 的运行都是以单线程的方式工做的,虽然有多种方式实现了对多线程的模拟(例如:JavaScript 中的 setinterval 方法,setTimeout 方法等),可是在本质上程序的运行仍然是由 JavaScript 引擎以单线程调度的方式进行的。在 HTML5 中引入的工做线程使得浏览器端的 JavaScript 引擎能够并发地执行 JavaScript 代码,从而实现了对浏览器端多线程编程的良好支持。ajax
HTML5 中的 Web Worker 能够分为两种不一样线程类型,一个是专用线程 Dedicated Worker,一个是共享线程 Shared Worker。两种类型的线程各有不一样的用途。下面对这两种工做线程做了详细的说明和描述。算法
在建立专用线程的时候,须要给 Worker 的构造函数提供一个指向 JavaScript 文件资源的 URL,这也是建立专用线程时 Worker 构造函数所须要的惟一参数。当这个构造函数被调用以后,一个工做线程的实例便会被建立出来。下面是建立专用线程代码示例:数据库
1
|
var worker = new Worker('dedicated.js');
|
专用线程在运行的过程当中会在后台使用 MessagePort 对象,而 MessagePort 对象支持 HTML5 中多线程提供的全部功能,例如:能够发送和接受结构化数据(JSON 等),传输二进制数据,而且支持在不一样端口中传输数据等。编程
为了在页面主程序接收从专用线程传递过来的消息,咱们须要使用工做线程的 onmessage 事件处理器,定义 onmessage 的实例代码以下:json
1
|
worker.onmessage = function (event) { ... };
|
另外,开发人员也能够选择使用 addEventListener 方法,它最终的实现方式和做用和 onmessage 相同。浏览器
就像前面讲述的,专用线程会使用隐式的 MessagePort 实例,当专用线程被建立的时候,MessagePort 的端口消息队列便被主动启用。所以,这也和工做线程接口中定义的 start 方法做用一致。缓存
若是要想一个专用线程发送数据,那么咱们须要使用线程中的 postMessage 方法。专用线程不只仅支持传输二进制数据,也支持结构化的 JavaScript 数据格式。在这里有一点须要注意,为了高效地传输 ArrayBuffer 对象数据,须要在 postMessage 方法中的第二个参数中指定它。实例代码以下:
1
2
3
4
5
6
|
worker.postMessage({
operation: 'list_all_users',
//ArrayBuffer object
input: buffer,
threshold: 0.8,
}, [buffer]);
|
共享线程能够由两种方式来定义:一是经过指向 JavaScript 脚本资源的 URL 来建立,而是经过显式的名称。当由显式的名称来定义的时候,由建立这个共享线程的第一个页面中使用 URL 会被用来做为这个共享线程的 JavaScript 脚本资源 URL。经过这样一种方式,它容许同域中的多个应用程序使用同一个提供公共服务的共享线程,从而不须要全部的应用程序都去与这个提供公共服务的 URL 保持联系。
不管在什么状况下,共享线程的做用域或者是生效范围都是由建立它的域来定义的。所以,两个不一样的站点(即域)使用相同的共享线程名称也不会冲突。
建立共享线程能够经过使用 SharedWorker() 构造函数来实现,这个构造函数使用 URL 做为第一个参数,便是指向 JavaScript 资源文件的 URL,同时,若是开发人员提供了第二个构造参数,那么这个参数将被用于做为这个共享线程的名称。建立共享线程的代码示例以下:
var worker = new SharedWorker('sharedworker.js', ’ mysharedworker ’ );
共享线程的通讯也是跟专用线程同样,是经过使用隐式的 MessagePort 对象实例来完成的。当使用 SharedWorker() 构造函数的时候,这个对象将经过一种引用的方式被返回回来。咱们能够经过这个引用的 port 端口属性来与它进行通讯。发送消息与接收消息的代码示例以下:
1
2
3
4
5
6
7
|
// 从端口接收数据 , 包括文本数据以及结构化数据
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 参数的构造函数建立的时候,它须要有一系列的处理流程来处理和记录它自己的数据和状态。下面咱们给出了工做线程的处理模型以下(注:因为 W3C 中工做线程的规范依然在更新,您读到这篇文章的时候可能看到已不是最新的处理模型,建议参考 W3C 中的最新规范):
1. 建立一个独立的并行处理环境,而且在这个环境里面异步的运行下面的步骤。
2. 若是它的全局做用域是 SharedWorkerGlobalScope 对象,那么把最合适的应用程序缓存和它联系在一块儿。
3. 尝试从它提供的 URL 里面使用 synchronous 标志和 force same-origin 标志获取脚本资源。
4. 新脚本建立的时候会按照下面的步骤:
5. 启动线程监视器,关闭孤儿线程。
6. 对于挂起线程,启动线程监视器监视挂起线程的状态,即时在并行环境中更改它们的状态。
7. 跳入脚本初始点,而且启动运行。
8. 若是其全局变量为 DedicatedWorkerGlobalScope 对象,而后在线程的隐式端口中启用端口消息队列。
9. 对于事件循环,等待一直到事件循环列表中出现新的任务。
10. 首先运行事件循环列表中的最早进入的任务,可是用户代理能够选择运行任何一个任务。
11. 若是事件循环列表拥有存储 mutex 互斥信号量,那么释放它。
12. 当运行完一个任务后,从事件循环列表中删除它。
13. 若是事件循环列表中还有任务,那么继续前面的步骤执行这些任务。
14. 若是活动超时后,清空工做线程的全局做用域列表。
15. 释放工做线程的端口列表中的全部端口。
工做线程的全局做用域仅仅限于工做线程自己,即在线程的生命周期内有效。规范中 WorkerGlobalScope 接口表明了它的全局做用域,下面咱们来看下这个接口的具体实施细节(WorkerGlobalScope 抽象接口)。
1
2
3
4
5
6
7
8
9
|
interface WorkerGlobalScope {
readonly attribute WorkerGlobalScope self;
readonly attribute WorkerLocation location;
void close();
attribute Function onerror;
};
WorkerGlobalScope implements WorkerUtils;
WorkerGlobalScope implements EventTarget;
|
咱们可使用 WorkerGlobalScope 的 self 属性来或者这个对象自己的引用。location 属性返回当线程被建立出来的时候与之关联的 WorkerLocation 对象,它表示用于初始化这个工做线程的脚步资源的绝对 URL,即便页面被屡次重定向后,这个 URL 资源位置也不会改变。
当脚本调用 WorkerGlobalScope 上的 close()方法后,会自动的执行下面的两个步骤:
1. 删除这个工做线程事件队列中的全部任务。
2. 设置 WorkerGlobalScope 对象的 closing 状态为 true (这将阻止之后任何新的任务继续添加到事件队列中来)。
工做线程之间的通讯必须依赖于浏览器的上下文环境,而且经过它们的 MessagePort 对象实例传递消息。每一个工做线程的全局做用域都拥有这些线程的端口列表,这些列表包括了全部线程使用到的 MessagePort 对象。在专用线程的状况下,这个列表还会包含隐式的 MessagePort 对象。
每一个工做线程的全局做用域对象 WorkerGlobalScope 还会有一个工做线程的线程列表,在初始化时这个列表为空。当工做线程被建立的时候或者拥有父工做线程的时候,它们就会被填充进来。
最后,每一个工做线程的全局做用域对象 WorkerGlobalScope 还拥有这个线程的文档模型,在初始化时这个列表为空。当工做线程被建立的时候,文档对象就会被填充进来。不管什么时候当一个文档对象被丢弃的时候,它就要从这个文档对象列举里面删除出来。
在工做线程的生命周期中,定义了下面四种不一样类型的线程名称,用以标识它们在线程的整个生命周期中的不一样状态:
因为 W3C 的 Web Worker 规范目前仍是处于完善阶段,没有造成最终的规范,本文也将上面线程的四种不一样状态的原文定义附在了后面。
对于类库和脚本的访问和引入,规范中规定可使用 WorkerGlobalScope 对象的 importScripts(urls) 方法来引入网络中的脚本资源。当用户调用这个方法引入资源的时候会执行下面的步骤来完成这个操做:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
/**
* 使用 importScripts 方法引入外部资源脚本,在这里咱们使用了数学公式计算工具库 math_utilities.js
* 当 JavaScript 引擎对这个资源文件加载完毕后,继续执行下面的代码。同时,下面的的代码能够访问和调用
* 在资源文件中定义的变量和方法。
**/
importScripts('math_utilities.js');
/**
* 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);
}
|
在 HTML5 中, WorkerUtils 接口的 navigator 属性会返回一个工做导航器对象(WorkerNavigator),这个对象定义而且表明了用户代理(即 Web 客户端)的标识和状态。所以,用户和 Web 脚本开发人员能够在多线程开发过程当中经过这个对象来取得或者肯定用户的状态。
WorkerUtils 抽象接口的 navigator 属性会返回一个 WorkerNavigator 用户接口,用于用户代理的识别的状态标识。咱们来看下 WorkerNavigator 接口的定义。
1
2
3
|
interface WorkerNavigator {};
WorkerNavigator implements NavigatorID;
WorkerNavigator implements NavigatorOnLine;
|
其中,有一点须要注意:若是接口的相对命名空间对象为 Window 对象的时候,WorkerNavigator 对象必定不能够存在,即没法再使用这个对象。
在讲解建立新的工做线程以前,咱们先看下 W3C 规范对工做线程的定义。工做线程规范中定义了线程的抽象接口类 AbstractWorker ,专用线程以及共享线程都继承自该抽象接口。专用线程以及共享线程的建立方法读者能够参考第一小节中的示例代码。下面是此抽象接口的定义。
1
2
3
4
5
6
|
[Supplemental, NoInterfaceObject]
interface AbstractWorker {
attribute Function onerror;
};
AbstractWorker implements EventTarget;
|
此外,该接口还定义了错误处理的事件处理器 onerror,当工做线程在通讯过程当中遇到错误时便会触发这个事件处理器。
1
2
3
4
5
6
7
|
[Constructor(in DOMString scriptURL)]
interface Worker : AbstractWorker {
void terminate();
void postMessage(in any message, in optional MessagePortArray ports);
attribute Function onmessage;
};
|
当建立完线程之后,咱们能够调用 terminate() 方法去终止一个线程。每一个专用线程都拥有一个隐式的 MessagePort 对象与之相关联。这个端口随着线程的建立而被建立出来,但并无暴露给用户。全部的基于这个端口的消息接收都以线程自己为目标。
1
2
3
4
|
[Constructor(DOMString scriptURL, optional DOMString name)]
interface SharedWorker : AbstractWorker {
readonly attribute MessagePort port;
};
|
共享线程同专用线程同样,当建立完线程之后,咱们能够调用 terminate() 方法去终止一个共享线程。
工做线程被建立出来之后,须要记录它的状态以及位置信息,在工做线程规范中定义了 WorkerLocation 来表示它们的位置。接口定义以下:
1
2
3
4
5
6
7
8
9
10
11
|
interface WorkerLocation {
// URL decomposition IDL attributes
stringifier readonly attribute DOMString href;
readonly attribute DOMString protocol;
readonly attribute DOMString host;
readonly attribute DOMString hostname;
readonly attribute DOMString port;
readonly attribute DOMString pathname;
readonly attribute DOMString search;
readonly attribute DOMString hash;
};
|
WorkerLocation 对象表示了工做线程脚本资源的绝对 URL 信息。咱们可使用它的 href 属性取得这个对象的绝对 URL。WorkerLocation 接口还定义了与位置信息有关的其它属性,例如:用于信息传输的协议(protocol),主机名称(hostname),端口(port),路径名称(pathname)等。
咱们能够写出不少的例子来讲明后台工做线程的合适的用法,下面咱们以几种典型的应用场景为例,用代码实例的形式讲解在各类需求背景下正确的使用它们。
工做线程最简单的应用就是用来作后台计算,而这种计算并不会中断前台用户的操做。下面咱们提供了一个工做线程的代码片断,用来执行一个相对来讲比较复杂的任务:计算两个很是大的数字的最小公倍数和最大公约数。
在这个例子中,咱们在主页面中建立一个后台工做线程,而且向这个工做线程分配任务(即传递两个特别大的数字),当工做线程执行完这个任务时,便向主页面程序返回计算结果,而在这个过程当中,主页面不须要等待这个耗时的操做,能够继续进行其它的行为或任务。
咱们把这个应用场景分为两个主要部分,一个是主页面,能够包含主 JavaScript 应用入口,用户其它操做 UI 等。另一个是后台工做线程脚本,即用来执行计算任务。代码片断以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<!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
>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
/**
* 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,把计算结果发送到主页面。
因为线程的构建以及销毁都要消耗不少的系统性能,例如 CPU 的处理器调度,内存的占用回收等,在通常的编程语言中都会有线程池的概念,线程池是一种对多线程并发处理的形式,在处理过程当中系统将全部的任务添加到一个任务队列,而后在构建好线程池之后自动启动这些任务。处理完任务后再把线程收回到线程池中,用于下一次任务调用。线程池也是共享线程的一种应用。
在 HTML5 中也引入了共享线程技术,可是因为每一个共享线程能够有多个链接,HTML5 对共享线程提供了和普通工做线程稍微有些区别的 API 接口。下面咱们提供几个例子来说述对共享线程的用法。
下面咱们给出一个例子:建立一个共享线程用于接收从不一样链接发送过来的指令,而后实现本身的指令处理逻辑,指令处理完成后将结果返回到各个不一样的链接用户。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
<!DOCTYPE html>
<
html
>
<
head
>
<
meta
charset
=
"UTF-8"
>
<
title
>Shared worker example: how to use shared worker in HTML5</
title
>
<script>
var
worker =
new
SharedWorker(
'sharedworker.js'
);
var
log = document.getElementById(
'response_from_worker'
);
worker.port.addEventListener(
'message'
,
function
(e) {
//log the response data in web page
log.textContent =e.data;
},
false
);
worker.port.start();
worker.port.postMessage(
'ping from user web page..'
);
//following method will send user input to sharedworker
function
postMessageToSharedWorker(input)
{
//define a json object to construct the request
var
instructions={instruction:input.value};
worker.port.postMessage(instructions);
}
</script>
</
head
>
<
body
onload
=
''
>
<
output
id
=
'response_from_worker'
>
Shared worker example: how to use shared worker in HTML5
</
output
>
send instructions to shared worker:
<
input
type
=
"text"
autofocus
oninput
=
"postMessageToSharedWorker(this);return false;"
>
</
input
>
</
body
>
</
html
>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
// 建立一个共享线程用于接收从不一样链接发送过来的指令,指令处理完成后将结果返回到各个不一样的链接用户。
/*
* define a connect count to trace connecting
* this variable will be shared within all connections
*/
var connect_number = 0;
onconnect = function(e) {
connect_number =connect_number+ 1;
//get the first port here
var port = e.ports[0];
port.postMessage('A new connection! The current connection number is '
+ connect_number);
port.onmessage = function(e) {
//get instructions from requester
var instruction=e.data.instruction;
var results=execute_instruction(instruction);
port.postMessage('Request: '+instruction+' Response '+results
+' from shared worker...');
};
};
/*
* this function will be used to execute the instructions send from requester
* @param instruction
* @return
*/
function execute_instruction(instruction)
{
var result_value;
//implement your logic here
//execute the instruction...
return result_value
}
|
在上面的共享线程例子中,在主页面即各个用户链接页面构造出一个共享线程对象,而后定义了一个方法 postMessageToSharedWorker 向共享线程发送来之用户的指令。同时,在共享线程的实现代码片断中定义 connect_number 用来记录链接到这个共享线程的总数。以后,用 onconnect 事件处理器接受来自不一样用户的链接,解析它们传递过来的指令。最后,定义一个了方法 execute_instruction 用于执行用户的指令,指令执行完成后将结果返回给各个用户。
这里咱们并无跟前面的例子同样使用到了工做线程的 onmessage 事件处理器,而是使用了另一种方式 addEventListener。实际上,这两种的实现原理基本一致,只有有些稍微的差异,若是使用到了 addEventListener 来接受来自共享线程的消息,那么就要使用 worker.port.start() 方法来启动这个端口。以后就能够像工做线程的使用方式同样正常的接收和发送消息。
多线程代理技术
随着多核处理器的流行,现代的计算机通常都拥有多核的 CPU,这也使得任务可以在处理器级别上并发执行。若是咱们要在一个具备多核 CPU 的客户端上用单线程去执行程序即处理业务逻辑,每每不能最大化的利用系统资源。所以,在这种状况下咱们能够将一个耗时或者复杂的任务拆分红多个子任务,把每个子任务分担给一个工做线程,这样多个工做现场就共同承担了单个线程的工做负载,同时又可以并发的去执行,最大化的利用了系统资源(CPU、内存、I/O 等)。
下面咱们向读者提供一个线程代理应用的例子:计算全球人口的数量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<!DOCTYPE html>
<
html
>
<
head
>
<
meta
charset
=
"UTF-8"
>
<
title
>Shared worker example: how to use delegation worker in HTML5</
title
>
<script>
var
worker =
new
SharedWorker(
'delegationworker.js'
);
var
log = document.getElementById(
'response_from_worker'
);
worker.onmessage =
function
(event) {
//resolve the population from delegation worker
var
resultdata=event.data;
var
population=resultdata.total_population;
var
showtext=
'The total population of the word is '
+population;
document.getElementById(
'response_from_worker'
).textContent = showtext;
};
</script>
</
head
>
<
body
onload
=
''
>
<
output
id
=
'response_from_worker'
>
Shared worker example: how to use delegation worker in HTML5
</
output
>
</
body
>
</
html
>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
/*
* define the country list in the whole word
* take following Array as an example
*/
var country_list = ['Albania','Algeria','American','Andorra','Angola','Antigua','....'];
// define the variable to record the population of the word
var total_population=0;
var country_size=country_list.length;
var processing_size=country_list.length;
for (var i = 0; i < country_size; i++)
{
var worker = new Worker('subworker.js');
//wrap the command, send to delegations
var command={command:'start',country:country_list[i]};
worker.postMessage(command);
worker.onmessage = update_results;
}
/*
* this function will be used to update the result
* @param event
* @return
*/
function storeResult(event)
{
total_population += event.data;
processing_size -= 1;
if (processing_size <= 0)
{
//complete the whole work, post results to web page
postMessage(total_population);
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
//define the onmessage hander for the delegation
onmessage = start_calculate;
/*
* resolve the command and kick off the calculation
*/
function start_calculate(event)
{
var command=event.data.command;
if(command!=null&&command=='start')
{
var coutry=event.data.country;
do_calculate(country);
}
onmessage = null;
}
/*
* the complex calculation method defined here
* return the population of the country
*/
function do_calculate(country)
{
var population = 0;
var cities=//get all the cities for this country
for (var i = 0; i < cities.length; i++)
{
var city_popu=0;
// perform the calculation for this city
//update the city_popu
population += city_popu;
}
postMessage(population);
close();
}
|
HTML5 Web Worker 的多线程特性为基于 Web 系统开发的程序人员提供了强大的并发程序设计功能,它容许开发人员设计开发出性能和交互更好的富客户端应用程序。本文不只仅详细讲述 HTML5 中的多线程规范。同时,也以几种典型的应用场景为例,以实例的形式讲解 HTML5 中多线程编程以及应用,为用户提供了详细而全面的参考价值,而且指导开发人员设计和构建更为高效和稳定的 Web 多线程应用。