web worker 简介
通常,浏览器执行某段程序的时候会阻塞直到运行结束后在恢复到正常状态,而HTML5的Web Worker就是为了解决这个问题。通过worker线程完成密集计算,避免程序的阻塞和页面的卡顿(fps过低)
示例
用fibonacci数列来模拟测试
worker-test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试 web worker</title>
</head>
<body>
<script>
function fibonacci(n) {
return n < 2 ? n : arguments.callee(n - 1) + arguments.callee(n - 2);
}
function testNoWorker() {
let start = Date.now();
fibonacci(38);
let end = Date.now();
console.log(end - start); // wait a long time..
}
function testUseWorker() {
let start = Date.now();
let worker = new Worker('worker.js');
worker.postMessage(38);
worker.addEventListener('message', function (event) {
let end = Date.now();
console.log('worker result: ', end -start);
});
console.log('can do other jobs, when worker is computing');
}
testNoWorker();
testUseWorker();
</script>
</body>
</html>
worker.js
function fibonacci(n) {
return n < 2 ? n : arguments.callee(n-1) + arguments.callee(n-2);
}
self.addEventListener('message', function (event) {
let result = fibonacci(event.data);
self.postMessage(result);
});
// 可用 setTimeout , setInterval
setTimeout(() => {
console.log('timeout..');
}, 100);
setInterval(() => {
console.log('setInterval...');
}, 200);
// 可发起ajax
fetch('data.json').then(res => res.json()).then(data => {console.log(data, '<--json data')});
// 可访问 location, navigator
console.log(location);
console.log(navigator);
// worker.js的执行上下文为 self (worker实例),
// self上的属性和方法可直接调用
console.log(typeof addEventListener);
console.log(typeof postMessage);
假设主页面需要多次执行耗时的操作(如: fibonacci), 可如下用worker来异步执行.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试 实例化多个 web worker</title>
</head>
<body>
<script>
function fibonacci(n) {
let start = Date.now();
let worker = new Worker('worker.js');
worker.addEventListener('message', function (event) {
let end = Date.now();
console.log('worker result: ', end - start);
});
worker.postMessage(n);
}
/* 同时跑多个worker, 会降低每个worker线程的性能;但总比阻塞页面要好 */
fibonacci(38);
console.log('after one');
fibonacci(38);
console.log('after two');
fibonacci(38);
console.log('after three');
console.log('can handle other jobs..');
</script>
</body>
</html>
跨域与脚本引入
在主页面实例化worker, new Worker('/url/to/worker.js')
worker脚本必须和主页面同域;在worker脚本中,可以 self.importScripts('url/to/script.js')
导入任何域的脚本, 多个 self.importScripts()
是顺序同步加载的
worker的方法
worker.terminate()
终止worker线程
限制
- 不能访问主页面的全局变量和函数,没有 window, document; 但可访问 location, navigator
- 支持setTimeout, setInterval, 可发起ajax
- worker不能访问和操作dom
- postMessage传的数据都会被复制,不会指向同一个内存地址