使用后台线程时不能访问页面或窗口对象,但是并不代表后台线程不能与页面之间进行数据交互。为了实现页面与 Web Workers 通信,可以调用 postMessage 函数传入所需数据,同时将建立一个监听器,用来监听由 Web Workers 发送到页面的消息。
为建立页面和 Web Workers 之间的通信,首先在页面中添加对 postMessage 函数的调用,如下所示。
document.getElementById('helloButton').onclick = function () {
worker.postMessage('Hi,How are you');
};
当用户单击按钮后,相应信息会被发送给 Web Workers ,然后将事件监听器添加到页面中,用来监听从 Web Workers 发来的信息。
worker.addEventListener('message', messageHandler, true);
function messageHandler(e) {
//process message from worker
}
编写 HTML5 Web Workers JavaScript 文件。在该文件中,需要添加事件监听器以监听发来的消息,并且通过调用 postMessage 函数实现与页面之间的通信。
为了完成页面与 Web Workers 之间的通信功能。首先,添加代码调用 postMessage 函数。例如,在 messageHandler 函数中可以添加如下代码。
function messageHandler(e) {
postMessage('worker says: ' + e.data + ' too');
}
接下来,在 Web Workers JavaScript 文件中添加事件监听器,以处理从页面发来的信息:
addEventListener('message', messageHandler, true);
接收到信息后会马上调用 messageHandler 函数以保证信息能及时返回。
通过 postMessage 函数将对象传递到 Worker 或者从中返回对象,这些对象将被自动转换为 JSON 格式。
var onmessage = function (e) {
postMessage(e.data);
};
注意:在 Worker 中进出的对象不能包含函数和循环引用,因为 JSON 不支持它们。
在 Web Workers 脚本中如果发生未处理的错误,会引发 Web Workers 对象的错误事件。特别是在调试用到 Web Workers 脚本时,对错误事件的监听就显得尤为重要。下面显示的是 Web Workers JavaScript 文件中的错误处理函数,它将错误记录在控制台上。
function errorHandler(e) {
console.log(e.message, e);
}
为了处理错误,还必须在主页上添加一个事件监听器:
worker.addEventListener('error', errorHandler, true);
当 Worker 发生运行时错误时,它的 onerror 事件就会被触发。该事件接收一个 error 的事件,该事件不会冒泡,并且可以取消。要取消该事件可以使用 preventDefault() 方法。该错误事件有以下 3 个属性。
Web Workers 不能自行终止,但能够被启用它们的页面所终止。调用 terminate 函数可以终止后台进程。被终止的 Web Workers 将不再响应任何信息或者执行任何其它计算。终止之后, Worker 不能被重新启动,但可以使用同样的 URL 创建一个新的 Worker 。
worker.terminate();
如果需要马上终止一个正在运行中的 Worker ,则可以调用它的 terminate() 方法:
myWorker.terminate();
这样一个 Worker 进程就被结束了。
完成主页面的设计。包括 HTML 结构和 CSS 样式。在主页脚本中创建一个主线程,定义请求数据为空,在主线程响应事件 onmessage 回调函数中处理后台返回的处理数据,并把它们显示在页面中。
修改主线程中的代码。在主线程中定义一个子线程(发送数据),让其随机生成 200 个数字,并返回这个随机数组。在该子线程的回调函数中再定义一个子线程(接收数据),把接收到的随机数组传递给它,并接收该线程过滤后的数组。
发送数据的子线程中创建了一个 200 个整数构成的随机数组。然后把它转换为字符串并返回,最后关闭该子线程。
接收数据子线程中对接收到的随机数组中挑选能被 3 整除的数字,然后拼接成字符串并返回。
JavaScript 一个最原始的缺陷就是它的单线程任务处理,这个局限性意味着一个长时间运行的进程会冻结主窗口。通常说的浏览器 UI 线程阻塞,这是由于主线程在处理所有的可视化元素及其相关任务,如绘制、刷新、动画、用户输入事件等。
这种线程过载的严重后果是页面被冻结,且用户不能再与 Web 应用进行交互。因此, Web 应用的用户体验就非常差,用户可能会关掉这个 Tab 或者整个浏览器。为了避免发生这种情况,浏览器已经引入一种保护机制,当脚本运行时间过长时,就会弹出警告。
但是,这种机制并不能正确分辨究竟是一段脚本编写有问题,还是这段脚本确实需要更多的时间来完成它的工作。尽管如此,由于它阻塞了 UI 线程,所以提示一下比让用户无限等待要好。
为了避免出现此类情况,传统做法是通过 setTimeout 和 setInterval 方法试图模拟并行任务,或者通过 XMLHttpRequest 对象,也可以异步地处理 HTTP 请求,避免从远程服务器载入资源时冻结 UI 。当然,有了 Web Workers 技术之后,情况会有很大的好转。