JS居然也可以多线程!

如果你刚刚开始使用JS,你会怀疑这句话,因为一开始所有人都会告诉你JS是一门单线程语言,多线程是后端独占的,并且告诉你为什么以及event Loop相关知识。并且嘱咐你这就以及足够应对我们的开发场景了。然而实际上,JS可以进行多线程。而且非常简单。

WebWorker:为前端解放多线程

WebWorker是HTML5引入的一项重要特性,它允许我们在浏览器中创建一个独立的后台线程,用于执行一些耗时的任务,而不会阻塞用户界面的渲染和交互。

使用WebWorker,我们可以轻松地将一些计算密集型的任务,比如图像处理、数据计算等,转移到后台线程中执行,释放主线程的压力,提高应用程序的响应速度和用户体验。

一个简单的示例代码,演示了如何使用WebWorker来实现一个计算斐波那契数列的任务:

// 主线程代码
const worker = new Worker('worker.js');
worker.postMessage(10); // 向Worker发送消息

worker.onmessage = function(event) {
  console.log(event.data); // 接收Worker返回的结果
};
// Worker线程代码(worker.js)
self.onmessage = function(event) {
  const n = event.data;
  const result = fibonacci(n); // 计算斐波那契数列
  self.postMessage(result); // 将结果发送给主线程
};

function fibonacci(n) {
  if (n <= 1) {
    return n;
  }
  return fibonacci(n - 1) + fibonacci(n - 2);
}

通过上面的代码,我们可以看到,主线程将计算任务交给了WebWorker,并通过postMessage方法发送了一个消息。Worker线程接收到消息后,执行计算任务,并通过postMessage方法将结果发送给主线程。这种分离计算任务和UI渲染的方式,大大提高了应用程序的性能和响应速度。

SharedWorker:让多个页面共享计算资源

SharedWorker允许多个页面共享同一个后台线程,从而实现更高效的资源利用和协同计算。
A页面

const worker = new SharedWorker('Sharedworker.js');
worker.port.onmessage = function(event) {
  console.log(event.data); // 接收SharedWorker返回的结果
};

worker.port.postMessage({ type: 'add', operands: [2, 3] });
 // 向SharedWorker发送消息

B页面

const worker = new SharedWorker('Sharedworker.js');
worker.port.onmessage = function(event) {
  console.log(event.data); // 接收SharedWorker返回的结果
};

worker.port.postMessage({ type: 'multiply', operands: [4, 5] });
 // 向SharedWorker发送消息

Sharedworker.js


const ports = [];

self.onconnect = function(event) {
  const port = event.ports[0];
  ports.push(port);

  port.onmessage = function(event) {
    const message = event.data;
    const result = calculate(message.type, message.operands); // 执行计算任务
    ports.forEach(port => port.postMessage(result)); // 将结果发送给所有连接的页面
  };
};

function calculate(type, operands) {
  if (type === 'add') {
    return operands.reduce((a, b) => a + b, 0);
  } else if (type === 'multiply') {
    return operands.reduce((a, b) => a * b, 1);
  }
}

通过上面的代码,我们可以看到,页面A和页面B分别与同一个SharedWorker建立连接,并通过postMessage方法向SharedWorker发送消息。SharedWorker接收到消息后,执行相应的计算任务,并将结果通过postMessage方法发送给所有连接的页面。

这种多页面共享计算资源的方式,不仅减少了重复计算,还实现了页面之间的数据共享和协同计算,提高了系统的整体性能和可扩展性。

使用限制

  • 同源策略:客户端工作线程受到同源策略的限制,即只能与同源的脚本进行通信。这意味着客户端工作线程只能与与其来源相同的脚本进行交互,无法直接与其他域的脚本进行通信。(SharedWorker)

  • 无法访问DOM:客户端工作线程不能直接访问或操作浏览器的DOM(文档对象模型)。这是为了避免多线程操作DOM引发的潜在竞态条件和不确定性。如果需要操作DOM,可以通过与主线程进行通信来委托主线程执行相关操作。

  • 无法访问某些API:客户端工作线程无法直接访问一些浏览器API,如window对象、document对象、alert()函数等。这些功能只能通过与主线程进行通信来间接访问。

  • 不是所有浏览器都支持:尽管现代浏览器普遍支持客户端工作线程,但并不是所有浏览器都支持该功能。一些旧版本的浏览器可能不支持或提供有限支持。

ServiceWorker:细粒度地缓存资源

service worker同样是workers的另一个类型。但是由于目前支持度不是很高,所以还是遇到很大的兼容性的问题,得不到广泛的使用。

同步API(如XHR和localStorage)不能在service worker中使用。

出于安全考量,Service workers只能由·HTTPS承载

具体的内容我会在未来专门书写一个PWA指南来更好的讲解该功能,先鸽了。

未曾清贫难成人,不经打击老天真。 自古英雄出炼狱,从来富贵入凡尘。 醉生梦死谁成气,拓马长枪定乾坤。 挥军千里山河在,立名扬威传后人。