Web Workers 分类及 5 个使用场景
这是 JavaScript 工作原理的第七章。
本系列持续更新中,Github 地址请查阅这里。
现在,我们将会剖析 Web Workers:我们将会综合比较不同类型的 workers,如何组合运用他们的构建模块来进行开发以及不同场景下各自的优缺点。最后,我们将会介绍 5 个 Web Workder 的使用场景。
在前面的详细介绍的文章中你已经清楚地了解到 JavaScript 是单线程的事实。然而,JavaScript 也允许开发者编写异步代码。
异步编程的局限性
前面我们了解到异步编程及其使用时机。
异步编程通过调度部分代码使之在事件循环中延迟执秆,这样就允许优先渲染程序界面,从而让程序运行流畅。
AJAX 请求是一个很好的异步编程的使用场景 。因为请求可能会花很长的时间,所以可以异步执行它们,然后在客户端等待数据返回的同时,运行其它代码。
// 假设使用 jQuery
jQuery.ajax({
url: 'https://api.example.com/endpoint',
success: function(response) {
// 当数据返回时候的代码
}
});
然而,这里会产生一个问题-AJAX 请求是由浏览器网页 API 进行处理的,可以异步执行其它代码吗?比如,假设成功回调的代码是 CPU 密集型的:
var result = performCPUIntensiveCalculation();
如果 performCPUIntensiveCalculation 不是一个 HTTP 请求而是一个会阻塞界面渲染的代码(比如大量的 for 循环),这样就没有办法释放事件循环和浏览器的 UI-浏览器会被冻结住且失去响应。
这意味着,异步函数只是是解决了一部分 JavaScript 的单线程限制。
在某些情况下,你可以通过使用 setTimeout 来很好地解决由于长时间计算所造成的 UI 阻塞。比如,通过把一个复杂的计算批量拆分为若干个setTimeout 调用 ,把它们放在事件循环的不同位置执行,然后这样就可以使得 UI 有时间进行渲染及响应。
让我们看一个计算数值数组的平均值的简单函数。
function average(numbers) {
var len = numbers.length,
sum = 0,
i;
if (len === 0) {
return 0;
}
for (i = 0; i < len; i++) {
sum += numbers[i];
}
return sum / len;
}
可以把以上代码重写为模拟异步:
function averageAsync(numbers, callback) {
var len = numbers.length,
sum = 0;
if (len === 0) {
return 0;
}
function calculateSumAsync(i) {
if (i < len) {
// 在事件循环中调用下一个函数
setTimeout(function() {
sum += numbers[i];
calculateSumAsync(i + 1);
}, 0);
} else {
// 到达数组末尾,调用回调
callback(sum / len);
}
}
calculateSumAsync(0);
}
这里利用 setTimeout 函数在事件循环中循序添加每一次计算。在每一次计算之间,将会有充足的时间来进行其它的计算和解冻浏览器。
Web Workders 来救场
HTML5 给我们带了很多开箱即用的好用的功能,包括:
SSE(之前文章中提到过并且和 WebSockets 进行了比较)
Geolocation
Application cache
Local Storage
Drag and Drop
Web Workers
Web Workers 是浏览器内置的线程所以可以被用来执行非阻塞事件循环的 JavaScript 代码。
屌爆了。整个 JavaScript 是基于单线程环境的而 Web Workers (部分)可以突破这方面的限制。
Web Workers 允许开发者把长时间运行和密集计算型的任务放在后台执行而不会阻塞 UI,这会使得应用程序运行得更加流畅。另外,这样就不用再使用 setTimeout