Web Workers
介绍
- JavaScript 采用单线程模型,所有任务只能在一个线程上完成,一次只能做一件事。
- Web Workers 是 HTML5 提供的一个javascript多线程解决方案
- web worker允许主线程创建worker线程,将任务分配在后台运行。这样高延迟,密集型的任务可以由worker线程负担,如此就不冻结用户界面
- Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。
补充:为什么js是单线程?
JavaScript作为浏览器脚本语言,主要用途是与用户互动,以及操作DOM,这决定了它只能是单线程,否则会带来很复杂的同步问题。比如若js同时拥有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除这个节点,那浏览器将不知所措。为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JS脚本创建多个线程,但子线程完全受主线程控制,且不得操作DOM,所以该标准并没有改变JS单线程的本质。
注意点
-
同源限制
分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。
-
DOM 限制
Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用
document
、window
、parent
这些对象。但是,Worker 线程可以navigator
对象和location
对象。 -
通信联系
Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息通信。
-
脚本限制
Worker 线程不能执行
alert()
方法和confirm()
方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求。 -
文件限制
Worker 线程无法读取本地文件,即不能打开本机的文件系统(
file://
),它所加载的脚本,必须来自网络。
使用
- 创建在分线程执行的js文件
//worker.js
var onmessage =function (event){ //不能用函数声明
var upper= event.data;//通过event.data获得发送来的数据
var result=upper.toUpperCase(); //处理主线程传过来的数据并返回给主线程
postMessage( result);//将处理好的数据发送会主线程
}
- 在主线程中的js中发消息并设置回调
//创建一个Worker对象并向它传递将在新线程中执行的脚本的URL
var worker = new Worker("worker.js");
//接收worker传过来的已处理的数据
worker.onmessage = function (event) {
console.log(event.data); //HELLO WORLD
};
//向worker发送数据
worker.postMessage("hello world");
应用练习
编程实现斐波那契数列(Fibonacci sequence)的计算F(0)=0,F(1)=1,..... F(n)=F(n-1)+F(n-2)
-
直接在主线程
响应慢,影响了页面的操作
var fibonacci =function(n) { return n <2 ? n : fibonacci(n -1) + fibonacci(n -2); }; console.log(fibonacci(48));
-
使用Worker在分线程
- 主线程
var worker = new Worker('worker2.js'); worker.addEventListener('message', function (event) { var timer2 = new Date().getTime(); console.log('结果:' + event.data, '时间:' + timer2, '用时:' + ( timer2 - timer )); }, false); var timer = new Date().getTime(); console.log('开始计算: ', '时间:' + timer); setTimeout(function () { console.log('定时器函数在计算数列时执行了', '时间:' + new Date().getTime()); }, 1000); worker.postMessage(40); console.log('我在计算数列的时候执行了', '时间:' + new Date().getTime());
-
分线程
var fibonacci =function(n) { return n <2 ? n : fibonacci(n -1) + fibonacci(n -2); }; var onmessage = function(event) { var n = parseInt(event.data, 10); postMessage(fibonacci(n)); };
不足
-
慢(肯定是比直接在主线程运行慢)
-
不能跨域加载JS
-
worker内代码不能访问DOM(更新UI)
- 打印分线程的this
- 分线程中的全局对象不在是window,所以在分线程中无法更新界面,无法使用window的方法,比如alert
-
不是每个浏览器都支持这个新特性