JavaScript一次只做一件事情,如果交给他太多的工作,他就会受不了,可能会受到一个Slow script的对话框,告诉你运行缓慢。而且只运行一个线程会占用大量计算能力,对你的用户界面或交互来说就所剩无几了,看上去缓慢甚至无响应。
HTML5增加了Web Worker。
Web Worker 的三大主要特征:能够长时间运行(响应),理想的启动性能以及理想的内存消耗。Web Worker 允许开发人员编写能够长时间运行而不被用户所中断的后台程序,去执行事务或者逻辑,并同时保证页面对用户的及时响应。
HTML5 之前的 JavaScript 的运行都是以单线程的方式工作的,虽然有多种方式实现了对多线程的模拟(例如:JavaScript 中的 setinterval 方法,setTimeout 方法等),但是在本质上程序的运行仍然是由 JavaScript 引擎以单线程调度的方式进行的。在 HTML5
中引入的工作线程使得浏览器端的 JavaScript 引擎可以并发地执行 JavaScript 代码,从而实现了对浏览器端多线程编程的良好支持。
工作线程无法访问主浏览器代码能够访问的很多运行时对象,比如DOM或主代码中的所有变量或函数。(为了高效)
专用线程Dedicated Worker
创建:
var worker=new Worker("worker.js");
发送消息:
worker.postMessage("ping");//发送字符串(可以发送数组,JSON对象,但是函数不行)
worker.postMessage({
operation: 'list_all_users',
//ArrayBuffer object
input: buffer,
threshold: 0.8,
}, [buffer]);//为了高效地传输 ArrayBuffer 对象数据,需要在 postMessage 方法中的第二个参数中指定它
接受消息:
worker.onmsessage=function(event){...}//addEventListener
event.data//消息
event.target//worker的引用
共享线程 Shared Worker
共享线程可以由两种方式来定义:一是通过指向 JavaScript 脚本资源的 URL 来创建,而是通过显式的名称。当由显式的名称来定义的时候,由创建这个共享线程的第一个页面中使用 URL 会被用来作为这个共享线程的 JavaScript 脚本资源 URL。通过这样一种方式,它允许同域中的多个应用程序使用同一个提供公共服务的共享线程,从而不需要所有的应用程序都去与这个提供公共服务的
URL 保持联系。
无论在什么情况下,共享线程的作用域或者是生效范围都是由创建它的域来定义的。因此,两个不同的站点(即域)使用相同的共享线程名称也不会冲突。
创建:
创建共享线程可以通过使用 SharedWorker() 构造函数来实现,这个构造函数使用 URL 作为第一个参数,即是指向 JavaScript 资源文件的 URL,同时,如果开发人员提供了第二个构造参数,那么这个参数将被用于作为这个共享线程的名称。创建共享线程的代码示例如下:
var worker = new SharedWorker('sharedworker.js', ’ mysharedworker ’ );
通信:
// 从端口接收数据 , 包括文本数据以及结构化数据
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 数据格式。
importScript(urls)函数可以直接导入js
当用户调用这个方法引入资源的时候会执行下面的步骤来完成这个操作:
1、如果没有给 importScripts 方法任何参数,那么立即返回,终止下面的步骤。
2、解析 importScripts 方法的每一个参数。
3、如果有任何失败或者错误,抛出 SYNTAX_ERR 异常。
4、尝试从用户提供的 URL 资源位置处获取脚本资源。
5、对于 importScripts 方法的每一个参数,按照用户的提供顺序,获取脚本资源后继续进行其它操作。
/**
* 使用 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);
}
终止工作线程:worker.terminate();
处理工作线程中的错误:
worker.onerror=function(error){
document.getElementById("output").innerHTML="There was an error in"+error.filename+"at line number"+error.lineno+": "+error.message;
}
不能插入新的<script>元素从工作线程建立JSOP请求,不过可以使用importScripts来建立
function makeRequest(){
importScript("http://SomeServer.com?callback=handleRequest");}
function handleRequest(response){
postMessage(response);}
makeRequest();
工作线程中使用setInterval,(setTimeout)反复完成同样的任务
一个例子:
使用工作线程做后台数值(算法)计算
工作线程最简单的应用就是用来做后台计算,而这种计算并不会中断前台用户的操作。下面我们提供了一个工作线程的代码片段,用来执行一个相对来说比较复杂的任务:计算两个非常大的数字的最小公倍数和最大公约数。
在这个例子中,我们在主页面中创建一个后台工作线程,并且向这个工作线程分配任务(即传递两个特别大的数字),当工作线程执行完这个任务时,便向主页面程序返回计算结果,而在这个过程中,主页面不需要等待这个耗时的操作,可以继续进行其它的行为或任务。
我们把这个应用场景分为两个主要部分,一个是主页面,可以包含主 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;
}
--------------------------
参考:h@ttp://www.ibm.com/developerworks/cn/web/1112_sunch_webworker/