1 进程与线程的区别
操作系统会为每个进程分配独立的内存空间(比如浏览器的每个tab就是一个进程),一个进程由一个或多个线程组成,同个进程下的各个线程之间共享程序的内存空间。
2.1 GUI 渲染线程
GUI 渲染线程负责渲染浏览器界面,解析 HTML,CSS,构建 DOM 树和 RenderObject 树,布局和绘制等。当界面需要重绘(Repaint)或由于某种操作引发回流(Reflow)时,该线程就会执行。
2.2 JavaScript 引擎线程
JavaScript 引擎线程负责解析 JavaScript 脚本并运行相关代码。 JavaScript 引擎一直等待着任务队列中任务的到来,然后进行处理,一个Tab页(Renderer 进程)中无论什么时候都只有一个 JavaScript 线程在运行 JavaScript 程序。
需要注意的是,GUI 渲染线程与 JavaScript 引擎线程是互斥的,所以如果 JavaScript 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染被阻塞。
2.3 事件触发线程
当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待 JavaScript 引擎的处理。这些事件可以是当前执行的代码块如定时任务、也可来自浏览器内核的其他线程如鼠标点击、AJAX 异步请求等,但由于 JavaScript 引擎是单线程的,所有这些事件都得排队等待 JavaScript 引擎处理。
2.4 定时触发器线程
浏览器定时计数器并不是由 JavaScript 引擎计数的,这是因为 JavaScript 引擎是单线程的,如果处于阻塞线程状态就会影响记计时的准确,所以通过单独线程来计时并触发定时是更为合理的方案。我们日常开发中常用的 setInterval 和 setTimeout 就在该线程中。
2.5 Http 异步请求线程
在 XMLHttpRequest 在连接后是通过浏览器新开一个线程请求, 将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件放到 JavaScript 引擎的处理队列中等待处理。
前面我们已经知道了,由于 JavaScript 引擎与 GUI 渲染线程是互斥的,如果 JavaScript 引擎执行了一些计算密集型或高延迟的任务,那么会导致 GUI 渲染线程被阻塞或拖慢。那么如何解决这个问题呢?嘿嘿,当然是使用本文的主角 —— Web Workers。
3:Web Worker
Web Worker 是 HTML5 标准的一部分,这一规范定义了一套 API,它允许一段 JavaScript 程序运行在主线程之外的另外一个线程中。Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。
关于主 副线程速度的一些个人看法
Web Worker的创建过程是异步的,在未创建完成之前如果postMessage了数据,那么这些数据将会暂时存放在一个临时队列,当 WebWorker创建成功后,这些数据才会迁移到WebWorker的执行队列,假设这里耗费了一些时间。另外postMessage数据的过程中,这些数据需要使用结构化克隆算法拷贝一份再传送,拷贝与传送也许需要时间,特别是对于一些文件对象来说需要的时间更久。当然,可以直接传送二进制数据,此时TypeArray就派上用场了。WebWorker是由webkit内核实现的,真正的计算速度我觉得应该和主线程相差无几,耗时操作应该包括以上几个方面。