这次javascrit栏目会逐步讲解 Web Workers,先说个简单的概念,接着讨论不同类型的Web Workers,他们的组成部分是如何一起工作的,以及不同场景下它们各自优势和限制。最后提供5个正确使用Web Workers 的场景。
这是JavaScript栏目专门探索javascript及其所构建的组件的系列文章。
这次我们会逐步讲解 Web Workers,先说个简单的概念,接着讨论不同类型的 Web Workers,他们的组成部分是如何一起工作的,以及不同场景下它们各自优势和限制。最后,提供5个正确使用 Web Workers 的场景。 正如我们前面文章讨论的那样,你应该知道 JavaScript 语言采用的是单线程模型。然而,JavaScript 也为开发人员提供了编写异步代码的机会。 异步编程的局限性以前的文章讨论过异步编程,以及应该在什么时候使用它。 异步编程可以让UI界面是响应式(渲染速度快)的,通过"代码调度",让需要请求时间的代码先放到在 event loop中晚一点再执行,这样就允许UI先行渲染展示。 异步编程的一个很好的用例就 AJAX 请求。由于请求可能花费大量时间,因此可以使用异步请求,在客户端等待响应的同时还可以执行其他代码。
然而,这带来了一个问题——请求是由浏览器的WEB API处理的,但是如何使其他代码是异步的呢?例如,如果成功回调中的代码非常占用CPU: var result = performCPUIntensiveCalculation(); 如果 这意味着异步函数只能解决一小部分 JavaScript 语言单线程中的局限性问题。 在某些情况下,可以使用 看一个简单的函数,计算一个数字数组的平均值:
以下是重写上述代码并“模拟”异步性的方法: function averageAsync(numbers, callback) {
var len = numbers.length,
sum = 0;
if (len === 0) {
return 0;
}
function calculateSumAsync(i) {
if (i < len) {
// Put the next function call on the event loop.
setTimeout(function() {
sum += numbers[i];
calculateSumAsync(i + 1);
}, 0);
} else {
// The end of the array is reached so we're invoking the callback.
callback(sum / len);
}
}
calculateSumAsync(0);
}使用setTimeout函数,该函数将在事件循环中进一步添加计算的每个步骤。在每次计算之间,将有足够的时间进行其他计算,从而可以让浏览器进行渲染。 Web Worker 可以解决这个问题HTML5为我们带来了很多新的东西,包括:
Web Worker 概述Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。这样的好处是,一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程(通常负责 UI 交互)就会很流畅,不会被阻塞或拖慢。 你可能会问:“JavaScript不是一个单线程的语言吗?” 事实上 JavaScript 是一种不定义线程模型的语言。Web Workers 不是 JavaScript 的一部分,而是可以通过 JavaScript 访问的浏览器特性。历史上,大多数浏览器都是单线程的(当然,这已经改变了),大多数 JavaScript 实现都入发生在浏览器中。Web Workers 不是在 Node.JS 中实现的。Node.js 中有类似的集群(cluster)、子进程概念(child_process),他们也是多线程但是和 Web Workers 还是有区别 。 值得注意的是,规范 中提到了三种类型的 Web Workers:
Dedicated Workers专用 Workers 只能被创建它的页面访问,并且只能与它通信。以下是浏览器支持的情况:
Shared Workers共享 Workers 在同一源(origin)下面的各种进程都可以访问它,包括:iframes、浏览器中的不同tab页(一个tab页就是一个单独的进程,所以Shared Workers可以用来实现 tab 页之间的交流)、以及其他的共享 Workers。以下是浏览器支持的情况:
Service workersService Worker 功能:
在目前阶段,Service Worker 的主要能力集中在网络代理和离线缓存上。具体的实现上,可以理解为 Service Worker 是一个能在网页关闭时仍然运行的 Web Worker。以下是浏览器支持的情况:
本文主要讨论 专用 Workers,没有特别声明的话,Web Workers、Workers都是指代的专用 Workers。 Web Workers 是如何工作Web Workers 一般通过脚本为 Worker 利用类线程间消息传递来实现并行性。它们保证界面的实时性、高性能和响应性呈现给用户。 Web Workers 在浏览器中的一个独立线程中运行。因此,它们执行的代码需要包含在一个单独的文件中。这一点很重要,请记住! 让我们看看基本 Workers 是如何创建的: var worker = new Worker('task.js');
为了启动创建的 Worker,需要调用 worker.postMessage(); Web Worker 通信为了在 Web Worker 和创建它的页面之间进行通信,需要使用 postMessage 方法新浏览器支持JSON对象作为方法的第一个参数,而旧浏览器只支持字符串。 来看一个示例,通过将 JSON 对象作为一个更“复杂”的示例传递,创建 Worker 的页面如何与之通信。传递字符串跟传递对象的方式也是一样的。 让我们来看看下面的 HTML 页面(或者更准确地说是它的一部分): <button onclick="startComputation()">Start computation</button>
<script>
function startComputation() {
worker.postMessage({'cmd': 'average', 'data': [1, 2, 3, 4]});
}
var worker = new Worker('doWork.js');
worker.addEventListener('message', function(e) {
console.log(e.data);
}, false);
</script>然后这是 worker 中的 js 代码: self.addEventListener('message', function(e) {
var data = e.data;
switch (data.cmd) {
case 'average':
var result = calculateAverage(data); // 从数值数组中计算平均值的函数
self.postMessage(result);
break;
default:
self.postMessage('Unknown command');
}
}, false);当单击该按钮时,将从主页调用 当消息到达时,实际的计算在worker中执行,而不会阻塞事件循环。Worker 检查传递的事件参数 在 Worker 作用域中,this 和 self 都指向 Worker 的全局作用域。 有两种方法可以停止 Worker:从主页调用 Broadcast ChannelBroadcast Channel API 允许同一原始域和用户代理下的所有窗口,iFrames 等进行交互。也就是说,如果用户打开了同一个网站的的两个标签窗口,如果网站内容发生了变化,那么两个窗口会同时得到更新通知。 还是不明白?就拿 Facebook 作为例子吧,假如你现在已经打开 了Facebook 的一个窗口,但是你此时还没有登录,此时你又打开另外一个窗口进行登录,那么你就可以通知其他窗口/标签页去告诉它们一个用户已经登录了并请求它们进行相应的页面更新。 // Connection to a broadcast channel
var bc = new BroadcastChannel('test_channel');
// Example of sending of a simple message
bc.postMessage('This is a test message.');
// Example of a simple event handler that only
// logs the message to the console
bc.onmessage = function (e) {
console.log(e.data);
}
// Disconnect the channel
bc.close()可以从下面这张图,在视觉上来清晰地感受 Broadcast Channel:
Broadcast Channel 浏览器支持比较有限:
消息的大小有两种方式发送消息给Web Workers:
Web Workers 可用的特性由于 JavaScript的多线程特性,Web工作者只能访问JavaScript特性的一个子集。以下是它的一些特点: Web Workers 由于具有多线程特性,因此只能访问 JavaScript 特性的子集。 以下是可使用特性列表:
Web Workers 的局限性遗憾的是,Web Workers 无法访问一些非常关键的 JavaScript 特性:
这意味着 Web Worker 不能操作 DOM (因此也不能操作 UI)。有时这可能很棘手,但是一旦你了解了如何正确使用 Web Workers,你就会开始将它们作为单独的“计算机”使用,而所有 UI 更改都将发生在你的页面代码中。 Workers 将为你完成所有繁重的工作,然后一旦完成再把结果返回给 page 页面。 处理错误和 JavaScript 代码一样,Web workers 里抛出的错误,你也需要进行处理。当 Worker 执行过程中如果遇到错误,会触发一个
例子如下:
在这里,可以看到我们创建了一个 worker 并开始侦听错误事件。
在 worker 内部(在 5个好的 Web Workers 应用实例到目前为止,我们已经列出了 Web Workers 的优点和局限性。现在让我们看看它们最强大的用例是什么:
以上就是JavaScript Web Workers的构建块及5个使用场景的详细内容,更多请关注模板之家(www.mb5.com.cn)其它相关文章! |
