HTML5之之web workers_动力节点动力节点Java学院整理学院整理
专用 Web Worker (Dedicated Web Worker) 提供了一个简单的方法使得 web 内容能够在后台运行脚本。下面通过本文给大家分享HTML5之web workers的相关知识,需要的的朋友
参考下吧
专用 Web Worker (Dedicated Web Worker) 提供了一个简单的方法使得 web 内容能够在后台运行脚本。一旦 worker 创建后,它可以向由它的创建者指定的事件监听函数传递消息,这样该 worker 生成
的所有任务就都会接收到这些消息。worker 线程能够在不干扰 UI 的情况下执行任务。另外,它还能够使用XMLHttpRequest(虽然responseXML与channel 两个属性值始终是null)来执行I/O 操作。本文通
过提供例子和细节补全了前面的文档。提供给 worker 的函数列出了 worker 所支持的函数。
Worker接口会生成真正的操作系统级别的线程,如果你不太小心,那么并发(concurrency)会对你的代码产生有趣的影响。然而,对于 web worker 来说,与其他线程的通信点会被很小心的控制,这意味
着你很难引起并发问题。你没有办法去访问非线程安全的组件或者是 DOM,此外你还需要通过序列化对象来与线程交互特定的数据。所以你要是不费点劲儿,还真搞不出错误来。生成 worker
创建一个新的 worker 十分简单。你所要做的就是调用Worker()构造函数,指定一个要在 worker 线程内运行的脚本的 URI,如果你希望能够收到 worker 的通知,可以将 worker 的onmessage属性设置成
一个特定的事件处理函数。
var myWorker = new Worker("my_task.js");
myWorker.onmessage = function (oEvent) {
console.log("Called back by the worker!");
};
或者,你也可以使用addEventListener():
var myWorker = new Worker("my_task.js");
myWorker.addEventListener("message", function (oEvent) {
console.log("Called back by the worker!");
}, false);
myWorker.postMessage(""); // start the worker.
例子中的第一行创建了一个新的 worker 线程。第三行为 worker 设置了message事件的监听函数。当 worker 调用自己的postMessage() 函数时就会调用这个事件处理函数。最后,第七行启动了 worker
线程。注意: 传入Worker构造函数的参数 URI 必须遵循同源策略。目前,不同的浏览器制造商对于哪些 URI 应该遵循同源策略尚有分歧;Gecko 10.0 (Firefox 10.0 / Thunderbird 10.0 / SeaMonkey
2.7) 及后续版本允许传入 data URI,而 Internet Explorer 10 则不认为 Blob URI 对于 worker 来说是一个有效的脚本。
传递数据传递数据
在主页面与 worker 之间传递的数据是通过拷贝,而不是共享来完成的。传递给worker 的对象需要经过序列化,接下来在另一端还需要反序列化。页面与 worker不会共享同一个实例,最终的结果就是在
每次通信结束时生成了数据的一个副本。大部分浏览器使用结构化拷贝来实现该特性。
在往下进行之前,出于教学的目的,让我们创建一个名为emulateMessage()的函数,它将模拟在从worker到主页面(反之亦然)的通信过程中,变量的「拷贝而非共享」行为:
function emulateMessage (vVal) {
return eval("(" + JSON.stringify(vVal) + ")");
}
// Tests
// test #1
var example1 = new Number(3);
alert(typeof example1); // object
alert(typeof emulateMessage(example1)); // number
// test #2
var example2 = true;
alert(typeof example2); // boolean
alert(typeof emulateMessage(example2)); // boolean
// test #3
var example3 = new String("Hello World");
alert(typeof example3); // object
alert(typeof emulateMessage(example3)); // string
// test #4
var example4 = {
"name": "John Smith",
"age": 43
};
alert(typeof example4); // object
alert(typeof emulateMessage(example4)); // object
// test #5
function Animal (sType, nAge) {
this.type = sType;
this.age = nAge;
}
var example5 = new Animal("Cat", 3);
alert(example5.constructor); // Animal
alert(emulateMessage(example5).constructor); // Object
拷贝而并非共享的那个值称为消息。再来谈谈worker,你可以使用postMessage() 将消息传递给主线程或从主线程传送回来。message事件的data属性就包含了从 worker 传回来的数据。
example.html: (主页面主页面):
var myWorker = new Worker("my_task.js");
myWorker.onmessage = function (oEvent) {
console.log("Worker said : " + oEvent.data);
};
myWorker.postMessage("ali");
my_task.js (worker):
postMessage("I\'m working before postMessage(\'ali\').");
onmessage = function (oEvent) {
postMessage("Hi " + oEvent.data);
};
注意:通常来说,后台线程 – 包括 worker –无法操作 DOM。如果后台线程需要修改 DOM,那么它应该将消息发送给它的创建者,让创建者来完成这些操作。
如你所见,worker与主页面之间传输的消息始终是「JSON 消息」,即使它是一个原始类型的值。所以,你完全可以传输JSON数据 和/或 任何能够序列化的数据类型:
postMessage({"cmd": "init", "timestamp": Date.now()});
传递数据的例子
例子 #1: 创建一个通用的 「异步eval()」
下面这个例子介绍了,如何在 worker 内使用eval()来按顺序执行异步的任何种类的 JavaScript 代码:
// Syntax: asyncEval(code[, listener])
var asyncEval = (function () {
var aListeners = [], oParser = new Worker("data:text/javascript;charset=US-ASCII,onmessage%20%3D%20function%20%28oEvent%29%20%7B%0A%09postMessage%28%7B%0A%09%09%22id%22%3A%20oEvent.data.id%2C%0A%09%09%22evaluated%22%3A%20eval%28oEvent.data.code%29%0A%09%7D%29%3B%0A%7D");
oParser.onmessage = function (oEvent) {
if (aListeners[oEvent.data.id]) { aListeners[oEvent.data.id](oEvent.data.evaluated); }
delete aListeners[oEvent.data.id];
};
return function (sCode, fListener) {
aListeners.push(fListener || null);
oParser.postMessage({
"id": aListeners.length - 1,
"code": sCode
});
};
})();
示例使用:
// asynchronous alert message...
asyncEval("3 + 2", function (sMessage) {
alert("3 + 2 = " + sMessage);
});
// asynchronous print message...
asyncEval("\"Hello World!!!\"", function (sHTML) {
document.body.appendChild(document.createTextNode(sHTML));
});