JS SharedWorker介绍/广播/Vue使用

  • 一、SharedWorker介绍
  • 二、SharedWorker使用
  • 1、兼容性
  • 2、创建
  • 3、通讯
  • 4、启动和关闭
  • 5、调试
  • 6、最简单demo
  • 6.1 SharedWorker.js 代码
  • 6.2 Page1.html 代码
  • 6.3 Page2.html 代码
  • 6.4 结果输出
  • 三、SharedWorker使用注意项
  • 四、广播示例
  • 4.1 SharedWorker.js 代码
  • 4.2 Page1.html 代码
  • 4.3 Page2.html 代码
  • 4.4 结果输出
  • 五、vue中使用
  • 5.1 建立子共享线程js
  • 5.2 vue文件使用


一、SharedWorker介绍

SharedWorker是Worker中的一种,中文名叫’共享线程‘,主要用于同源页面之间的共享线程和数据,常用于浏览器不同标签页面之间进行通讯。

如果还不了解Worker,可以查看这里

二、SharedWorker使用

1、兼容性

ie不支持,chrome完全支持

兼容性判断:if (!SharedWorker) { throw new Error('当前浏览器不支持SharedWorker') }

vue使用 Redis Vue使用shareWorker_html

2、创建

  1. 创建共享线程的js文件:SharedWorker.js
  2. 创建共享线程 const worker = new SharedWorker('SharedWorker.js')
  3. 每创建一个worker,如果参数url都一样,那么会视为使用同一个共享线程,共享线程会分配一个端口port来区分不同使用者

3、通讯

  1. 主线程和共享线程都是通过 postMessage() 方法来发送消息
  2. 接收消息都是使用onmessage = (e)=>{},或者 addEventListener('message', (e)=>{})

4、启动和关闭

线程通过 worker.port.start() 启动
线程通过 worker.port.close() 关闭
使用单页应用的时候记得关闭,否则常驻

5、调试

SharedWorker不能直接在页面调试面板查看,需要浏览器输入 chrome://inspect/#workers 然后点击inspect查看

vue使用 Redis Vue使用shareWorker_html_02

6、最简单demo

这里使用最简单的demo来说明使用方式,

  • SharedWorker.js 共享线程,里面存储计时器counter
  • page1.html 刷新页面,通知counter+1
  • page2.html 刷新页面,查看counter

6.1 SharedWorker.js 代码

// 计时器
let counter = 0

// 监听连接
self.addEventListener('connect', (e) => {
  const port = e.ports[0]
  port.onmessage = (res) => {
    console.log('共享线程接收到信息:', res.data)
    switch (res.data) {
      case 'counter++':
        counter++
        break
    }
    console.log('counter:', counter)
    port.postMessage(counter)
  }
})

6.2 Page1.html 代码

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>SharedWorker示例-页面1</title>
  </head>
  <body>
    <h1>SharedWorker示例-页面1</h1>
    <script>
      // 兼容性判断
      if (!SharedWorker) {
        throw new Error('当前浏览器不支持SharedWorker')
      }

      // 创建共享线程
      const worker = new SharedWorker('SharedWorker.js')

      // 启动线程端口
      worker.port.start()

      // 向共享线程发送消息
      worker.port.postMessage('counter++')

      // 线程监听消息
      worker.port.addEventListener('message', (e) => {
        console.log('page1页面共享线程counter值:', e.data)
      })
    </script>
  </body>
</html>

6.3 Page2.html 代码

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>SharedWorker示例-页面2</title>
  </head>
  <body>
    <h1>SharedWorker示例-页面2</h1>
    <script>
      // 兼容性判断
      if (!SharedWorker) {
        throw new Error('当前浏览器不支持SharedWorker')
      }

      // 创建共享线程
      const worker = new SharedWorker('SharedWorker.js')

      // 启动线程端口
      worker.port.start()

      // 向共享线程发送消息
      worker.port.postMessage('get counter')

      // 线程监听消息
      worker.port.addEventListener('message', (e) => {
        console.log('page2页面共享线程counter值:', e.data)
      })
    </script>
  </body>
</html>

6.4 结果输出

vue使用 Redis Vue使用shareWorker_vue.js_03

三、SharedWorker使用注意项

SharedWorker是Worker的一种应用,所以注意项和Worker一致

  1. 共享线程的上下文为自身,可以通过self,或者this来获取;
  2. 主线程和共享线程之间传递的消息是复制而不是共享,也就是说如果传递参数是一个对象,那么程序会使用JSON方式来编码/解码对象;
  3. 主线程和子线程是不同上下文,不同作用域,子线程不能调用主线程的dom和方法,具体
    不能使用
  • window 对象
  • document 对象
  • parent 对象
  • alert()
  • confirm()

可以使用

  • navigator 对象
  • location 对象(只读)
  • XMLHttpRequest
  • setTimeout()/clearTimeout() 和 setInterval()/clearInterval()
  • 应用缓存
  • 使用 importScripts() 方法导入外部脚本
  • 生成其他 Web Worker

四、广播示例

上面的demo只演示了不同页面共用了共享线程的数据,但刷新page1并不会主动通知page2数据变更,page2必须刷新才能获取新数据,那么如果实现广播效果呢?

下面demo实现广播效果,即 共享线程会向所有端口发送消息

  • SharedWorker.js 共享线程,存储计时器counter,counter变更会通知page1和page2
  • page1.html 刷新页面,通知counter+1
  • page2.html 刷新页面,通知counter+1

4.1 SharedWorker.js 代码

核心在于把所有连接的端口存起来

let counter = 0 // 计时器
let ports = [] // 存储所有连接端口的数组

// 监听连接
self.addEventListener('connect', (e) => {
  const port = e.ports[0]
  // 把端口对象存起来
  ports.push(port)

  // 监听消息
  port.onmessage = (res) => {
    console.log('共享线程接收到信息:', res.data)
    switch (res.data) {
      case 'counter++':
        counter++
        break
    }
    console.log('当前counter:', counter)

    // 向所有端口广播
    ports.forEach((p) => {
      p.postMessage(counter)
    })
  }
})

4.2 Page1.html 代码

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>SharedWorker示例-页面1</title>
  </head>
  <body>
    <h1>SharedWorker示例-页面1</h1>
    <script>
      // 兼容性判断
      if (!SharedWorker) {
        throw new Error('当前浏览器不支持SharedWorker')
      }

      // 创建共享线程
      const worker = new SharedWorker('SharedWorker.js')

      // 启动线程端口
      worker.port.start()

      // 向共享线程发送消息
      worker.port.postMessage('counter++')

      // 线程监听消息
      worker.port.addEventListener('message', (e) => {
        console.log('page1页面共享线程counter值:', e.data)
      })
    </script>
  </body>
</html>

4.3 Page2.html 代码

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>SharedWorker示例-页面2</title>
  </head>
  <body>
    <h1>SharedWorker示例-页面2</h1>
    <script>
      // 兼容性判断
      if (!SharedWorker) {
        throw new Error('当前浏览器不支持SharedWorker')
      }

      // 创建共享线程
      const worker = new SharedWorker('SharedWorker.js')

      // 启动线程端口
      worker.port.start()

      // 向共享线程发送消息
      worker.port.postMessage('counter++')

      // 线程监听消息
      worker.port.addEventListener('message', (e) => {
        console.log('page2页面共享线程counter值:', e.data)
      })
    </script>
  </body>
</html>

4.4 结果输出

vue使用 Redis Vue使用shareWorker_前端_04

五、vue中使用

5.1 建立子共享线程js

建立共享线程js:根目录/public/shared-worker/SharedWorker.js,代码如下:

// 计时器
let counter = 0

// 监听连接
self.addEventListener('connect', (e) => {
  const port = e.ports[0]
  port.onmessage = (res) => {
    console.log('共享线程接收到信息:', res.data)
    switch (res.data) {
      case 'counter++':
        counter++
        break
    }
    console.log('counter:', counter)
    port.postMessage(counter)
  }
})

5.2 vue文件使用

建立vue文件,代码如下

<template>
  <div><h1>SharedWorker使用</h1></div>
</template>

<script>
export default {
  created() {
    // 兼容性判断
    if (!window.SharedWorker) {
      throw new Error('当前浏览器不支持SharedWorker')
    }

    // 创建共享线程
    this.worker = new SharedWorker('/shared-worker/SharedWorker.js')

    // 启动线程端口
    this.worker.port.start()

    // 向共享线程发送消息
    this.worker.port.postMessage('counter++')

    // 线程监听消息
    this.worker.port.addEventListener('message', this.messageHandle)
  },
  methods: {
    // 消息处理
    messageHandle(e) {
      console.log('SharedWorker共享线程counter值:', e.data)
    },
  },
  destroyed() {
    // 记得销毁线程
    this.worker.port.removeEventListener('message', this.messageHandle)
    this.worker.port.close()
    this.worker = null
  },
}
</script>

兄弟,都看到这里了,点个赞再走呗