WebWorker——JavaScript也可以“多线程”

简介: 虽然JavaScript是单线程的,但是浏览器是多线程的啊,我们可以借助浏览器再跑一个JavaScript线程来帮助主JavaScript线程减轻压力,JavaScript之所以是单线程的原因是要保持数据的一致性,防止多个线程修改数据导致数据不一致,所以虽然可以使用worker,但也要遵循一些规范

前言


这里不要被标题误导,我打引号了,JavaScript并不能实现多线程(至少到目前为止,未来应该也不会)。

虽然JavaScript是单线程的,但是浏览器是多线程的啊,我们可以借助浏览器再跑一个JavaScript线程来帮助主JavaScript线程减轻压力,JavaScript之所以是单线程的原因是要保持数据的一致性,防止多个线程修改数据导致数据不一致,所以虽然可以使用worker,但也要遵循一些规范

  • 同源限制:分配给 Web Worker 线程运行的脚本文件,必须与主线程的脚本文件同源
  • DOM 限制:Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用 document、window、parent 这些对象。但是,Worker 线程可以访问 navigator 对象和 location 对象。
  • 通信联系:Worker 线程和主线程不再同一个上下文环境,它们不能直接通信,必须通过消息完成。
  • 脚本限制:Worker 线程不能执行 alert()confirm() 方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求
  • 文件限制:Worker 线程无法读取本地文件,即不能打开本地的文件系统(file://) ,它所加载的脚本,必须来自网络


创建worker


在使用worker时我们需要使用构造方法Worker实例化一个worker实例,传入worker文件的地址或者使用字符串转URL,例如

// 方法一
const worker = new Worker('./worker.js')
// 方法二
const code = `
  // worker's code
`
const buffer = new Blob([code])
const url = URL.createObjectURL(buffer)
const worker = new Worker(url)
复制代码

创建worker对象后:

  • 使用postMessage方法可以向worker发送消息,消息可以是任何类型,包括二进制;
  • 使用onmessage方法用来监听worker的消息;
  • 使用onerror方法用来监听worker线程的报错;
  • 使用terminate方法用来结束worker线程。
function startWorker() {
  const worker = new Worker('./worker.js')
  worker.postMessage({ x: 1, y: 2 })
  worker.onmessage = ({ data }) => {
    alert(data.data);
  }
  worker.onerror = (e) => {
    console.log(`[ERROR: Line ${e.lineno}] in ${e.filename}: ${e.message}`);
  }
}
复制代码

worker内,通过self来访问worker自身全局,

  • 使用onmessage方法处理主进程中通过postMessage方法触发的事件;
  • 使用postMessage方法向主线程发送数据,同样可以是任何数据类型;
  • worker线程中也可以引入其他js文件,使用importScripts(path)来引入;
  • worker可以使用close方法来主动关闭线程。
self.onmessage = ({ data }) => {
  // 一般使用worker来处理耗时任务,所以使用定时器模拟
  setTimeout(() => {
    self.postMessage({ data: data.x + data.y })
    throw new Error('抛出异常')
    self.close()
  }, 5000)
}
复制代码

以上类似onmessage的形式,均可以通过addEventListener来代替


实战练习


任务说明

在HTML页面中通过按钮触发worker事件:运算、退出……

main.js

const worker = new Worker('./worker.js')
worker.addEventListener('message', ({ data }) => {
  console.log(data);
})
worker.addEventListener('error', (e) => {
  console.log(`[ERROR: Line ${e.lineno}] in ${e.filename}: ${e.message}`);
})
function cal() {
  const num1 = document.getElementById('num1').value
  const num2 = document.getElementById('num2').value
  worker.postMessage({ cmd: 'cal', data: { num1, num2 } })
}
function exit() {
  worker.postMessage({ cmd: 'exit' })
  // 或者worker.terminate()
}
复制代码

Worker.js

self.addEventListener('message', ({ data }) => {
  switch (data.cmd) {
    case 'cal':
      const result = Number(data.data.num1) + Number(data.data.num2)
      if (isNaN(result)) {
        throw new Error('Input Type Error')
      } else {
        self.postMessage(result)
      }
      break
    case 'exit':
      self.close()
      break
    default:
      self.postMessage('Unknown command')
  }
})
复制代码

index.html

<body>
  num1: <input type="text" id="num1" />
  num2: <input type="text" id="num2" />
  <button type="button" onclick="cal()">计算</button>
  <button type="button" onclick="exit()">关闭</button>
</body>
复制代码

效果演示:

1682519770(1).png


应用场景


WebWorker 带来后台计算能力,WebWorker 自身是由 Webkit 多线程实现,但它并没有为 JavaScript 语言带来多线程编程特性,我们现在仍然不能在 JavaScript 代码中创建并管理一个线程,或者主动控制线程间的同步与锁等特性。Web Worker 只是浏览器(宿主环境)提供的一个能力 / API。而且它不支持 IE。

使用专用线程进行数学运算Web Worker 最简单的应用就是用来做后台计算,而这种计算并不会中断前台用户的操作

图像处理通过使用从 Canvas 或者 Video 元素中获取的数据,可以把图像分割成几个不同的区域并且把它们推送给并行的不同 Workers 来做计算

大量数据的检索当需要在调用 AJAX 后处理大量的数据,如果处理这些数据所需的时间长短非常重要,可以在 Web Worker 中来做这些,避免干扰 UI 线程。

背景数据分析由于在使用 Web Worker 的时候,我们有更多潜在的 CPU 可用时间,我们现在可以考虑一下 JavaScript 中的新应用场景。我们现在可以考虑一下 JavaScript 中的新应用场景。例如,我们可以想像在不影响 UI 体验的情况下实时处理用户输入。利用这样一种可能,我们可以想像一个像 Word(Office Web Apps 套装)一样的应用:当用户打字时后台在词典中进行查找,帮助用户自动纠错等等。

相关文章
|
2天前
|
移动开发 JavaScript 前端开发
Web Worker:JavaScript的后台任务解决方案
Web Worker:JavaScript的后台任务解决方案
|
3天前
|
移动开发 JavaScript 前端开发
【JavaScript技术专栏】Web Worker在JavaScript中的应用
【4月更文挑战第30天】HTML5的Web Worker API解决了JavaScript单线程性能瓶颈问题,允许在后台线程运行JS代码。本文介绍了Web Worker的基本概念、类型、用法和应用场景,如复杂计算、图像处理和数据同步。通过实例展示了搜索建议、游戏开发和实时数据分析等应用,并提醒注意其无法直接访问DOM、需消息传递通信以及移动端资源管理。Web Worker为前端开发提供了多线程能力,提升了Web应用性能和用户体验。
|
3天前
|
JavaScript 前端开发
JS 单线程还是多线程,如何显示异步操作
JS 单线程还是多线程,如何显示异步操作
24 2
|
10月前
|
数据采集 Web App开发 JavaScript
如何使用Selenium自动化Firefox浏览器进行Javascript内容的多线程和分布式爬取
在本文中,我们将介绍如何使用Selenium自动化Firefox浏览器进行Javascript内容的多线程和分布式爬取。我们将以一个简单的示例为例,抓取百度搜索结果页面中的标题和链接,并将结果保存到本地文件中。我们将使用Python语言编写代码,并使用爬虫代理服务器来隐藏我们的真实IP地址。
105 0
如何使用Selenium自动化Firefox浏览器进行Javascript内容的多线程和分布式爬取
|
JavaScript
Arcgis js多线程克里金插值初体验
最近做关于雨量插值的项目,本来使用后台的GP工具做的,但是处理时间比较长需要十几秒钟左右,所以研究怎么通过前台来计算。
96 0
|
前端开发 JavaScript
【worker】js中的多线程
因为下个项目中要用到一些倒计时的功能,所以就提前准备了一下,省的到时候出现一下界面不友好和一些其他的事情。正好趁着这个机会也加深一下html5中的多线程worker的用法和理解。 Worker简介     JavaScript 语言采用的是单线程模型,也就是说,所有任务只能在一个线程上完成,一次只能做一件事。
1321 0
|
JavaScript 前端开发 网络协议
|
JavaScript 前端开发 HTML5
web worker 是运行在后台的 JavaScript,不会影响页面的性能。
http://www.w3school.com.cn/html5/html_5_webworkers.asp
976 0
|
JavaScript 安全 前端开发
|
1天前
|
缓存 JavaScript 前端开发
JavaScript:get和post的区别,2024年最新3-6岁儿童学习与发展指南心得体会
JavaScript:get和post的区别,2024年最新3-6岁儿童学习与发展指南心得体会