概述

web worker就是在web应用程序中使用的worker。这个worker是独立于web主线程的,在后台运行的线程。

web worker的优点就是可以将工作交给独立的其他线程去做,这样就不会阻塞主线程。


一、使用步骤(web worker)

创建worker

创建一个基础的worker,通过传入脚本url地址,即可创建一个worker实例:

const work = new Worker(url);

消息通信

主进程:

// 监听接收worker进程信息
work.onmessage = (e) => console.log(`接收到worker传递的信息:${e.data}`);
// 发送信息到worker进程
work.postMessage('内容');

传递的数据类型包含:String、Number、Object、Array等JavaScript标准类型。

worker子进程:

// 监听接收主进程信息
self.onmessage = (e) => console.log(`接收到主进程发送的信息:${e.data}`);
// 发送信息到主进程
self.postMessage('内容');

在子进程中,self代表worker子进程的全局对象,也可以用this代替self,或者省略也行。

销毁worker

work.terminate();

简单示例

主进程代码:

const work = new Worker('work.js');
work.postMessage('hello worker')
work.onmessage = (e) => {
	console.log(`主进程收到了子进程发出的信息:${e.data}`);
	// 主进程收到了子进程发出的信息:你好,我是子进程!
	work.terminate();
};

worker子进程代码(work.js):

onmessage = (e) => {
	console.log(`收到了主进程发出的信息:${e.data}`); 
	//收到了主进程发出的信息:hello worker
	postMessage('你好,我是子进程!');
}

二、数据共享

主线程与 Worker 之间的通信是拷贝关系,Worker 对通信内容的修改,不会影响到主线程。但是以拷贝方式发送二进制数据,会造成性能问题,为了解决这个问题,JavaScript 允许主线程把对象引用直接转移给子线程,对象引用转移后,原先上下文就无法访问此对象了,需要在 Web Workers 再次将对象还原到主线程上下文后,主线程才能正常访问被转交的对象。这种转移数据的方法,叫做Transferable Objects。

let arr = new ArrayBuffer(100);
worker.postMessage(arr, [arr]);

三、外部引用

在worker子进程中,还可以引用其他的js文件到worker中进行使用,代码如下:

worker子进程

importScripts('./importScript.js');
console.log(importName); // 外部引用的js
console.log(start(2)); // 4

importScript.js

importName = '外部引用的js';
let start = (e) => e ** 2 ;

四、自动创建

通常情况下,worker是需要加载一个单独的js文件,但是也可以通过一些方法加载页面中的一些方法函数,原理就是把函数方法转换成一个blob类型之后,再转换成一个url类型,如下:

// 方式1,函数直接转换
function workCode() {
	onmessage = (e) => {
		postMessage('你好,我是子进程!');
	}
}
workBlob = new Blob([`(${workCode.toString ()})()`]); // 把函数转成一个自执行函数
workBlob = new Blob([workCode.toLocaleString().match(/(?:\/\*[\s\S]*?\*\/|\/\/.*?\r?\n|[^{])+\{([\s\S]*)\}$/)[1]]) // 把函数的主体内容拿出来进行转换

// 方式2,通过字符串的方式
const workCode  = `
	onmessage = (e) => {
		postMessage('你好,我是子进程!');
	}
`
workBlob = new Blob ([workCode]);

// 创建方法
const url = URL.createObjectURL(workBlob);
const worker = new Worker(url);

五、其他worker的使用

electron中使用worker

如果需要再electron中使用worker的话,需要在创建界面的时候需把 webPreferences 中的 nodeIntegrationInWorker 选项设置为true;

const win = new BrowserWindow(
	……
	webPreferences: {
		nodeIntegrationInWorker: true
	}
})

根据官方版本升级日志中,发现在4.2.9之后加入worker功能。在开启worker设置之后,可以在worker子进程中使用require等功能。

nodejs中使用worker

个人了解并不算多,待以后更新,可以参考nodejs官方网站。

六、共享worker(SharedWorker)

共享worker可以让多个页面共同使用一个worker,根据指定共同js脚本url来共享子进程,从而可以通过一个worker和多个主进程进行通信,可使用的场景:多页面数据传输、跨页面交互等功能。

示例代码:

页面1

const work = new SharedWorker('./work_share.js');
work.port.start();
work.port.postMessage('我是界面1');
work.port.onmessage = function(e) {
	console.log(e.data);
	// 收到了信息:我是界面1
}

页面2

const work = new SharedWorker('./work_share.js');
work.port.start();
work.port.postMessage('我是界面2');
work.port.onmessage = function(e) {
	console.log(e.data);
	// 收到了信息:我是界面2
}

共享worker(work_share.js)

let savePorts = [];
onconnect = function(e) {
    var port = e.ports[0];
    savePorts.push(port);
    port.addEventListener('message', function(e) {
    	sendMessage(e.data);
    });
    port.start();
}
let sendMessage = (info) => {
	for(let p = 0;p < savePorts.length; p++) savePorts[p].postMessage(`当前共享页面个数:${savePorts.length},收到了信息:${info}`);
}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐