自 JavaScript 诞生以来,还没有办法在浏览器 UI 线程之外运行代码。Web Worker 线程 API 改变了这种状况,它引入一个接口,使代码运行而不占用浏览器 UI 线程的时间。
Web Worker 线程对网页应用来说是一个潜在的巨大性能提升,因为新的 Web Worker 在自己的线程中运行JavaScript。这意味着,Web Worker 线程中的代码运行不仅不会影响浏览器 UI,而且也不会影响其它 Web Worker 线程中运行的代码。
关于Web Worker,最重要的是要知道它所执行的JavaScript代码完全在另一个作用域中,与当前网页中的代码不共享作用域。在Web Worker中,同样有一个全局对象和其他对象以及方法。但是,Web Worker中的代码不能访问DOM,也无法通过任何方式影响页面的外观。
Web Worker中的全局对象是 worker 对象本身。也就是说,在这个特殊的全局作用域中, this 和 self 引用的都是 worker 对象。为便于处理数据,Web Worker本身也是一个最小化的运行环境。
1. 最小化的 navigator 对象,包括 onLine 、 appName 、 appVersion 、 userAgent 和platform 属性;
2.只读的 location 对象;3.setTimeout() 、 setInterval() 、 clearTimeout() 和 clearInterval() 方法4.XMLHttpRequest 构造函数。
显然,Web Worker的运行环境与页面环境相比,功能是相当有限的。
当页面在 worker 对象上调用 postMessage()
时,数据会以异步方式被传递给 worker ,进而触发 worker 中的 message事件。为了处理来自页面的数据,同样也需要创建一个 onmessage 事件处理程序。
//Web Worker内部的代码
self.onmessage = function(event){
var data = event.data;
//别忘了,默认的sort()方法只比较字符串
data.sort(function(a, b){
return a – b;
});
self.postMessage(data);
};
大家看清楚,这里的 self 引用的是Worker全局作用域中的 worker 对象(与页面中的 Worker 对象不同一个对象)。Worker完成工作后,通过调用 postMessage()
可以把数据再发回页面。例如,下面的例子假设需要Worker对传入的数组进行排序,而Worker在排序之后又将数组发回了页面。
传递消息就是页面与Worker相互之间通信的方式。在Worker中调用 postMessage()
会以异步方式触发页面中Worker实例的 message 事件。如果页面想要使用这个Worker,可以这样:
//在页面中
var data = [23,4,7,9,2,14,6,651,87,41,7798,24],
worker = new Worker(“WebWorkerExample01.js”);
worker.onmessage = function(event){
var data = event.data;
//对排序后的数组进行操作
};
//将数组发送给worker排序
worker.postMessage(data);
排序的确是比较消耗时间的操作,因此转交给Worker做就不会阻塞用户界面了。另外,把彩色图像转换成灰阶图像以及加密解密之类的操作也是相当费时的。
考虑这样一个例子,解析一个很大的 JSON 字符串。假设数据足够大,至少需要 500 毫秒才能完成解析任务。很显然时间太长了以至于不能允许 JavaScript 在客户端上运行它,因为它会干扰用户体验。此任务难以分解成用于定时器的小段任务,所以Worker线程成为理想的解决方案。
总结:之前讲解了解决同步阻塞的问题包括异步与任务分割,今天增加了一种 Web Worker 的方法创建额外线程执行 JavaScript代码。
推荐阅读相关联的文章:《浏览器UI线程更新机制》、《 时间分片》