blog
blog copied to clipboard
Web Workers 草案翻译
基于11.27日的草案版本,在线地址
摘要
这份Spec定义了一个API,这个API使web应用开发者能够生成与他们的主页面并行的、在后台运行的worker脚本。这也使得,只要将消息传递作为协作机制,就能实现类线程的操作。
1. 简介
1.1. 范畴
本节是非正式的
这份Spec定义了一个用于运行与用户界面脚本独立的后台脚本的API。
这使得持续运行一些脚本,而不被响应点击或者其他用户交互的脚本打断,成为可能。而且,也使得长时任务可以被持续运行,而不用让出调度权来使得页面保持响应性。
Worker(这些后台脚本就叫这个)是相对而言比较重的,并且也不想被大规模地创建出来。例如,为一个4M大小的图片的每个像素创建一个worker是不合适的。下面的例子将展示一些worker恰当的用法。
一般而言,worker具有较长的存活期,有一个比较大的启动性能开销并且每个实例有略高的内存消耗。
1.2. 示例
本节是非正式的
worker有许多用途。下述子章节展示了几种用途。
1.2.1. 进行后台数值运算的worker
本节是非正式的
worker最简单的用途是,运行计算密集型任务而不打断用户的交互。
在这个例子中,主文档派生一个worker(naively)来计算素数,并展示最近被找到的素数。
住文档页面如下所述:
示例1 main.html
<!DOCTYPE HTML>
<html>
<head>
<title>Worker example: One-core computation</title>
</head>
<body>
<p>The highest prime number discovered so far is: <output id="result"></output></p>
<script>
var worker = new Worker('worker.js');
worker.onmessage = function (event) {
document.getElementById('result').textContent = event.data;
};
</script>
</body>
</html>
调用Worker()
构造器将会创建一个worker,并返回一个Worker
对象用于表示worker,该对象被用于和worker通信。返回对象的onmessage事件handler将使得代码可以从worker接收消息。
worker本身的代码如下所述:
示例2 worker.js
var n = 1;
search: while (true) {
n += 1;
for (var i = 2; i <= Math.sqrt(n); i += 1)
if (n % i == 0)
continue search;
// 找到素数
postMessage(n);
}
The bulk of this code is simply an unoptimised search for a prime number. The postMessage() method is used to send a message back to the page when a prime is found.
这份代码中的大部分都只是未经优化的素数搜索。postMessage()
方法被用于找到新素数后向页面回传数据。
1.2.2. 用于后台I/O的worker
本节是非正式的
在这个示例中,主文档使用了两个worker,一个用于以固定地频率获取股票更新,而另一个用于处理用户请求的搜索查询。
主页面代码如下
示例3 main.html
<!DOCTYPE HTML>
<html>
<head>
<title>Worker example: Stock ticker</title>
<script>
// Ticker
var symbol = 'GOOG'; // default symbol to watch
var ticker = new Worker('ticker.js');
// Searcher
var searcher = new Worker('searcher.js');
function search(query) {
searcher.postMessage(query);
}
// Symbol selection UI
function select(newSymbol) {
symbol = newSymbol;
ticker.postMessage(symbol);
}
</script>
</head>
<body onload="search('')">
<p><output id="symbol"></output> <output id="value"></output></p>
<script>
ticker.onmessage = function (event) {
var data = event.data.split(' ');
document.getElementById('symbol').textContent = data[0];
document.getElementById('value').textContent = data[1];
};
ticker.postMessage(symbol);
</script>
<p><label>Search: <input type="text" autofocus oninput="search(this.value)"></label></p>
<ul id="results"></ul>
<script>
searcher.onmessage = function (event) {
var data = event.data.split(' ');
var results = document.getElementById('results');
while (results.hasChildNodes()) // Clear previous results
results.removeChild(results.firstChild);
for (var i = 0; i < data.length; i += 1) {
// Add a list item with a button for each result
var li = document.createElement('li');
var button = document.createElement('button');
button.value = data[i];
button.type = 'button';
button.onclick = function () { select(this.value); };
button.textContent = data[i];
li.appendChild(button);
results.appendChild(li);
}
};
</script>
<p>(The data in this example is not real. Try searching for "Google" or "Apple".)</p>
</body>
</html>
这两个worker使用了一个公共的库来进行实际的网络请求。这个库如下所示:
示例4 io.js
function get(url) {
try {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, false);
xhr.send();
return xhr.responseText;
} catch (e) {
return ''; // Turn all errors into empty results
}
}
股票更新的worker如下所述:
示例5 ticker.js
importScripts('io.js');
var timer;
var symbol;
function update() {
postMessage(symbol + ' ' + get('stock.cgi?' + symbol));
timer = setTimeout(update, 10000);
}
onmessage = function (event) {
if (timer)
clearTimeout(timer);
symbol = event.data;
update();
};
搜索查询的worker代码如下所示:
示例6 search.js
importScripts('io.js');
onmessage = function (event) {
postMessage(get('search.cgi?' + event.data));
};
1.2.3. shared worker简介
本节是非正式的
本节用一个Hello World的示例介绍了shared worker。shared worker使用一些稍微不同的API,因为每个woker都可能有多个连接。
第一个示例展示了你该怎样连接一个worker,以及一个worker如何在页面连接上它的时候回传信息。接收道德消息将在log中展示。
下面是HTML页面:
示例7 main.html
<!DOCTYPE HTML>
<title>Shared workers: demo 1</title>
<pre id="log">Log:</pre>
<script>
var worker = new SharedWorker('test.js');
var log = document.getElementById('log');
worker.port.onmessage = function(e) { // Note: Not worker.onmessage!
log.textContent += '\n' + e.data;
}
</script>
下面是js代码
示例8 test.js
onconnect = function(e) {
var port = e.ports[0];
port.postMessage('Hello World!');
}
通过改变两件事,第二个例子扩展了第一个示例。首先,消息用addEventListener()
接收而不是用event handler 的IDL属性;其次,一个消息被发送给worker,使得worker发回另一个消息。接收道德消息也将在log中展示。
下面是HTML代码:
示例9 main.html
<!DOCTYPE HTML>
<title>Shared workers: demo 2</title>
<pre id="log">Log:</pre>
<script>
var worker = new SharedWorker('test.js');
var log = document.getElementById('log');
worker.port.addEventListener('message', function(e) {
log.textContent += '\n' + e.data;
}, false);
worker.port.start(); // Note: Needed when using addEventListener
worker.port.postMessage('ping');
</script>
这是worker的代码
示例10 test.js
onconnect = function(e) {
var port = e.ports[0];
port.postMessage('Hello World!');
port.onmessage = function(e) {
port.postMessage('pong'); // Not e.ports[0].postMessage!
// e.target.postMessage('pong'); // Also works
}
}
最后这个例子被扩展到展示两个页面如何与同一个worker通信;在这个例子中下,第二个页面仅仅是第一个页面的一个iframe,但是在一个完全独立的独立定级浏览上下文(就是浏览器的不同窗口 / 标签页)中也有相同的原理。
这是外层的html页面:
示例11
<!DOCTYPE HTML>
<title>Shared workers: demo 3</title>
<pre id="log">Log:</pre>
<script>
var worker = new SharedWorker('test.js');
var log = document.getElementById('log');
worker.port.addEventListener('message', function(e) {
log.textContent += '\n' + e.data;
}, false);
worker.port.start();
worker.port.postMessage('ping');
</script>
<iframe src="inner.html"></iframe>
这是内层的html页面:
示例12
<!DOCTYPE HTML>
<title>Shared workers: demo 3 inner frame</title>
<pre id=log>Inner log:</pre>
<script>
var worker = new SharedWorker('test.js');
var log = document.getElementById('log');
worker.port.onmessage = function(e) {
log.textContent += '\n' + e.data;
}
</script>
这是worker的代码:
示例13
var count = 0;
onconnect = function(e) {
count += 1;
var port = e.ports[0];
port.postMessage('Hello World! You are connection #' + count);
port.onmessage = function(e) {
port.postMessage('pong');
}
}
1.2.4. 用shared worker共享状态
本节是非正式的
翻译规范真是累活啊