blog icon indicating copy to clipboard operation
blog copied to clipboard

Web Workers 草案翻译

Open renaesop opened this issue 8 years ago • 1 comments

基于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共享状态

本节是非正式的

renaesop avatar Nov 22 '16 09:11 renaesop

翻译规范真是累活啊

FTAndy avatar Dec 22 '16 09:12 FTAndy