什么是Web Workers?
Web Workers是HTML5提供的一个JavaScript多线程解决方案。
实例说明
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web Workers Study</title>
</head>
<body>
<input type="text" placeholder="数值" id="num">
<button id="btn">计算</button>
<script>
// 1 1 2 3 5 8 13 21 f(n) = f(n-1) + f(n-2)
function fibonacci(n) {
return n<=2 ? 1 : fibonacci(n-1)+fibonacci(n-2);
}
var input = document.getElementById("num");
document.getElementById('btn').onclick = function() {
var number = input.value;
var result = fibonacci(number);
var t = Date.now();
alert(result);
console.log(Date.now() - t);
}
</script>
</body>
</html>
网页输入一个数字12,弹出框显示结果为144,Console窗口显示运行时间为890毫秒。
如果输入数字50,则要过1.7分钟才会出现弹出窗口显示结果12586269025。在1.7分钟期间,页面处于“计算状态”,不能在输入框输入数字。
Web Workers解决尴尬
Web Workers将负责该计算,同时不冻结页面(计算的同时可以在输入框输入数字)。
Web Workers负责的计算属于子线程,子线程受控于主线程,且不得操作DOM。因此,该标准没有改变JS单线程的本质。
以上代码通过Web Wokers处理,实际代码如下显示:
- WebWorkers.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web Workers Study</title>
<!-- <script type="text/javascript" src="work.js"></script> -->
</head>
<body>
<input type="text" placeholder="数值" id="num">
<button id="btn">计算</button>
<script type="text/javascript">
var input = document.getElementById("num");
document.getElementById('btn').onclick = function() {
var number = input.value;
// 创建一个worker对象
var worker = new Worker('worker.js');
// 向分线程发送消息
worker.postMessage(number);
console.log('主线程向分线程发送数据' + number);
// 绑定接收消息监听(异步事件,位置放在那里没关系)
worker.onmessage = function (event) {
console.log('主线程接收分线程返回的结果' + event.data);
alert(event.data);
}
}
</script>
</body>
</html>
- woker.js
在浏览器中输入file:///c:/SuniorYang/iLearn/js/WebWorkers.html,输入数字12,点击“计算”,报错!!
Uncaught DOMException: Failed to construct 'Worker': Script at 'file:///C:/SuniorYang/iLearn/js/worker.js' cannot be accessed from origin 'null'.
at HTMLButtonElement.document.getElementById.onclick (file:///C:/SuniorYang/iLearn/js/WebWorkers.html:18:26)
document.getElementById.onclick @ WebWorkers.html:18
因为worker不同访问本地文件,所以会提示错误。
解决方案
- npm install -g http-server
- http-server
启动http-server之后,在浏览器输入http://127.0.0.1:8080/js/WebWorkers.html,输入数字12,点击“计算”
页面响应时间较短,可以正常弹出计算结果和打印消息。如果输入数字50,则计算时间较长。
计算期间,可以在页面输入新数字52。
图解代码执行过程
、
worker任务作为异步任务存放在消息队列中,等待执行栈中的主线程为后返回异步执行结果。应用:城市下拉列表选择某一城市后,位于该城市下面的乡镇对加载显示。
Web Workers不足
- 不足一:运行比较慢
使用分线程,不是因为速度快,而是因为不堵塞主线程,不冻结主界面
- 不足二:worker内代码不能访问DOM
worker.js
// 1 1 2 3 5 8 13 21 f(n) = f(n-1) + f(n-2)
function fibonacci(n) {
return n<=2 ? 1 : fibonacci(n-1)+fibonacci(n-2);
}
var onmessage = function(event) { // 不能用函数声明
var number = event.data; // 通过event获得主线程发送来的数据
console.log('分线程接收到主线程发送的数据:' + number);
var result = fibonacci(number);
postMessage(result); // 将获取到的数据发送给主线程
console.log('分线程向主线程返回数据:'+result);
alert(result);
}
alert(result); 无法运行。console是浏览器方法,与window无关。
alert是window的方法,在分线程中无法使用。分线程对象不是window,所有分线程无法更新界面。
这就是与JS是单线程不冲突的原因。
- 不足三:不能跨域访问
跨域:www.baidu.com,通过baidu.com访问 sina.com