前端工程师们必定有过这样的体验,当一个页面加载了大量的 js 文件时,用户界面可能会短暂地“冻结”。这很好理解,由于 js 是单线程的语言。咱们再走的极端点,一段 js 中出现了 while(){}
的死循环,这时再去点击页面的 DOM 元素,将不会触发事件,事实上,这些异步的事件都排成了队列,只等页面的 js 渲染完后去执行(从setTimeout谈JavaScript运行机制),而此时渲染进入了死循环,因此出现了用户界面被“冻结”的现象。html
而实际的开发中,虽然不会出现相似的死循环,可是大量的 js 渲染仍是会影响用户体验的,此时咱们但愿这段耗时的 js 最好能异步去执行,setTimeout
是一个好的方法,可是 H5 提供了更好的办法,Web Worker! Web Worker 规范经过让 Javascript 在后台运行解决了这个问题。浏览器实现 Web Worker 规范的方式有不少种,可使用线程、后台进程或者运行在其余处理器核心上的进程,等等。具体的实现细节其实没有那么重要,重要的是开发人员如今能够放心地运行 Javascript,而没必要担忧会影响用户体验了。前端
既然 Worker 是 H5 你们庭的,那么 ie6 之辈就能够一边去了,详细的浏览器兼容性能够参考 http://caniuse.com/#search=workerajax
咱们来看这样一段代码:浏览器
<div style='width:100px;height:100px;background-color:red'></div> <script> document.querySelector('div').onclick = function() { console.log('hello world'); }; function fibonacci(n) { return n < 2 ? n : arguments.callee(n - 1) + arguments.callee(n - 2); } console.log(fibonacci(36)); </script>
页面上写了一个 div,而后监听了它的 click 事件,而且在 js 中须要计算斐波那契数列的第 36 项,并将它输出。这样的页面用户体验是很是差的,若是 fibonacci 不执行完,div 的 click 事件是没法及时响应的,而递归求解斐波那契数列项是至关耗时的!这样一段耗时的 js 代码,交给 worker 来作正合适!前端工程师
Worker 的使用方法很简单。app
实例化 Worker 对象并传入要执行的 Javascript 文件名就能够建立一个新的 Web Worker:异步
var worker = new Worker('worker.js');
这段代码会致使浏览器下载 worker.js,但只有 Worker 接收到消息才会实际执行文件中的代码。要给 Worker 传递消息,可使用 postMessage() 方法,好比我要告诉 Worker 须要求斐波那契数列的第 36 项:函数
worker.postMessage(36);
咱们来看看 Worker 是怎么接收消息的。当页面在 worker 对象上调用 postMessage()时,数据会以异步方式传递给 worker,进而触发 worker 中的 message 事件。为了处理来自页面的数据,一样也要建立一个 onmessage 事件处理程序。(worker.js 代码)post
self.onmessage = function(event) { var data = event.data; console.log(fibonacci(data)); }; function fibonacci(n) { return n < 2 ? n : arguments.callee(n - 1) + arguments.callee(n - 2); }
页面能够传数据给 Worker,Worker 固然也能够回传,页面经过 message 事件进行监听:this
worker.onmessage = function(event) { var data = event.data; };
Worker 是经过 message 和 error 事件与页面通讯的。来自 Worker 的数据保存在 event.data 中。Worker 不能完成给定的任务时会触发 error 事件。具体来讲,Worker 内部的 Javascript 在执行过程当中只要遇到错误,就会触发 error 事件。发生 error 事件时,事件对象中包含三个属性:filename、lineno 和 message,分别表示错误的文件名、代码行号和完整的错误信息:
worker.onerror = function(event) { console.log(event.filename, event.lineno, event.message); };
咱们建议使用 worker 时最好写上 error 事件,就像使用 ajax 时总要写上获取失败时的补救操做同样。
完整代码(运行 demo 必须起个本地服务):
html 文件:
<div style='width:100px;height:100px;background-color:red'></div> <script> document.querySelector('div').onclick = function() { console.log('hello world'); }; var worker = new Worker('worker.js'); worker.postMessage(36); worker.onmessage = function(event) { var data = event.data; console.log(data) }; worker.onerror = function(event) { console.log(event.filename, event.lineno, event.message); }; </script>
worker.js 文件:
self.onmessage = function(event) { var data = event.data; var ans = fibonacci(data); this.postMessage(ans); }; function fibonacci(n) { return n < 2 ? n : arguments.callee(n - 1) + arguments.callee(n - 2); }
简单小结:
WEB主线程:
worker新线程:
关于 Web Worker,最重要的是要知道它所执行的 Javascript 代码彻底在另外一个做用域中,与当前网页中的代码不共享做用域。在 Web Worker 中,一样有一个全局对象(worker 对象自己,this 和 self 引用的都是 worker 对象自己)和其余对象以及方法。Web Worker 中的代码不能访问 DOM。那么 Worker 里的代码能访问哪些对象,拥有哪些方法?
任什么时候候都能停止 Worker。在 worker.js 中,咱们能够用 self.close()
方法,而在页面中,咱们能够用 worker.terminal()
方法,这时 error 和 message 事件也不会触发了。