众多跨标签页通信方式,你知道哪些?(二)

书接上回,由于时间原因,还有几种情况没有总结,今天抽时间总结一下,其他情况请查看这里,众多跨标签页通信方式,你知道哪些?

以下则是常用的通信方法

  • BroadCast Channel
  • Service Worker
  • LocalStorage + window.onstorage 监听
  • Shared Worker 定时器轮询(setInterval)
  • IndexedDB 定时器轮询(setInterval)
  • cookie 定时器轮询(setInterval)
  • window.open + window.postMessage(非同源也可)
  • Websocket (非同源也可)

IndexedDB 定时器轮询(setInterval)

  • IndexedDB是一种底层的API,用于在客户端存储大量的结构化数据。
  • 它是一种事务型数据库系统,是一种基于JavaScript面向对象数据库,有点类似于NoSQL(非关系型数据库)。
  • IndexDB本身就是基于事务的,我们只需要指定数据库模式,打开与数据库的连接,然后检索和更新一系列事务即可。

indexedDB的详细使用请看这里

下面就简单演示先通信的过程,就是在两个同源页面进行获取数据。

js 复制代码
// 页面一
<button>新增</button>
<button>查询</button>
<button>删除</button>
<button>修改</button>
<script src="db.js"></script>
js 复制代码
// 页面二
<script>
    function openDB() {
      return new Promise((resolve,reject) => {
        const dbRequest = indexedDB.open("zhDB", 3)
        let db = null
        dbRequest.onsuccess = function(event) {
          db = event.target.result
          resolve(db)
        }
      })
    }
    const getAllData = async (db) => {
      return new Promise((resolve, reject) => {
        const transaction = db.transaction("users", "readwrite")
        const store = transaction.objectStore("users")
        const res = store.getAll()
        res.onerror = () => {
          reject([])
        }

        res.onsuccess = () => {
          resolve(res.result)
        }
      })
    }

    let infoData = []
    openDB().then(db => {
      setInterval(async () => { 
        const data = await getAllData(db)
        if(infoData.length !== data.length) {
          infoData = data
          console.log("infoData", infoData)
        }
      }, 1000)
    })
</script>

[具体代码请访问](cross-page-communication/IndexDB at main · zhang-glitch/cross-page-communication · GitHub)

mdn对于cookie各个属性及注意事项讲的非常清楚,可以在复习一下。cookie

这种跨页面通信方式也是在同源页面下才可以使用的。

js 复制代码
// 页面一
<script>
    document.cookie = "name=zh;path=/;domain=127.0.0.1;";
    console.log("cookie", document.cookie)
  </script>
js 复制代码
// 页面二
<script>
    // 获取指定cookie字段
    function getCookie(key) {
      return document.cookie.split(';').map(c => c.trim()).find(item => item.includes(`${key}=`))?.replace(`${key}=`, "")
    }
    const cookie = document.cookie
    console.log("全部cookie", cookie)
    let cookieName = ""
    setInterval(() => {
      if(getCookie("name") !== cookieName) {
        console.log("前一次cookie name", cookieName)
        console.log("当前cookie name", getCookie("name"))
        cookieName = getCookie("name")
      }
    }, 1000)
  </script>

window.open + window.postMessage

window.postMessage() 方法可以安全地实现跨源通信。所以这种方式也是一种可以在非同源的页面进行通信的方式。

这里用到了window.open来打开一个页面,因为我们在向其他页面发送消息时,需要拿到目标页面的引用。具体请看mdn

通信的大致过程就是

  • 我们通过window.open打开target页面。
  • 获取到target页面引用,然后调用postMessage方法,该方法参数一是发送的数据,参数二是哪些源可以接收到该消息,该参数指定目标页面必须和指定的源协议,域名,端口号一致才可以监听到消息
  • 目标页面接收到消息后,对比event.origin,如果是发送方则可以使用postMessage回复消息。
js 复制代码
// 页面一
<button id="openBtn">打开index2.html窗口</button>
<input type="text" id="text">
<button id="btn">发送数据</button>
<script>
    const text = document.querySelector("#text")
    const btn = document.querySelector("#btn")
    const openBtn = document.querySelector("#openBtn")
    let index2Window = null
    window.name = "页面一"
    openBtn.onclick = () => {
      // 使用hmserve库启动一个服务
      index2Window = window.open("http://localhost:8888/index2.html")
    }

    btn.onclick = () => {
      console.log("index2Window", index2Window)
      // 发送的数据
      // 指定哪些窗口能接收到消息事件
      index2Window?.postMessage({
        data: text.value
      }, "http://localhost:8888")
    }

    // 监听数据的回复
    window.addEventListener("message", (event) => {
      if(event.origin.includes("http://localhost:8888")) {
        console.log("event", event)
      }else {
        console.log("不安全数据")
      }
    })
</script>
js 复制代码
// 页面二
<script>
    window.name = "页面二"
    window.addEventListener("message", (event) => {
      // 为了数据安全,确定来源
      if(event.origin.includes("http://127.0.0.1")) {
        console.log("event", event)
        // 回复数据
        event.source.postMessage({
          data: "回复数据"
        }, event.origin)
      }else {
        console.log("不安全数据")
      }
    })
</script>

Websocket

在我们跨标签页通信中,WebSocket服务器就相当于中间人。就像Service Worker,Shared Worker通信方式一样,当我们接收到一个页面传递来的消息后,我们再将消息分发给其他页面。这也得益于websocket强大的服务器向客户端主动发送消息的能力。

这种方式也是可以在非同源页面进行通信的。

js 复制代码
// 创建一个websocket服务器,这里使用ws快速创建
const {WebSocketServer} = require("ws")

// 创建wb服务器
const wbss = new WebSocketServer({
  port: 3000
})

// 保存客户端链接实例
const clients = []

// 客户端连接时触发
wbss.on("connection", (client) => {
  clients.push(client)
  console.log("clients:1 客户端连接数", clients.length);

  // 绑定当前客户端连接,获取消息
  client.on('message', function message(data) {
    console.log('data', data);
    // 将消息传递给其他客户端
    clients.forEach(c => {
      if(c !== client) {
        c.send(data)
      }
    })
  });

  // 客户端断开连接(关闭或者刷新)
  client.on("close", () => {
    const findIndex = clients.findIndex(c => c === client)
    clients.splice(findIndex, 1)
    console.log("clients:2 客户端连接数", clients.length);
  })
})
js 复制代码
// 页面一
<input type="text" id="text">
<button id="btn">发送数据</button>
<script>
    const text = document.querySelector("#text")
    const btn = document.querySelector("#btn")

    // 和服务器建立连接
    const ws = new WebSocket("ws://localhost:3000")

    btn.onclick = () => {
      ws.send(JSON.stringify({
        data: text.value
      }))
    }

    ws.onmessage = (event) => {
      console.log("event", event)
    }

    // 关闭窗口或者刷新时关闭服务器连接
    window.onbeforeunload = () => {
      ws.close()
    }
</script>
js 复制代码
// 页面二
<script>
    // 和服务器建立连接
    const ws = new WebSocket("ws://localhost:3000")

    ws.onmessage = (event) => {
      console.log("event", event)
      ws.send("我接收倒了消息")
    }

     // 关闭窗口或者刷新时关闭服务器连接
    window.onbeforeunload = () => {
      ws.close()
    }
</script>

所有的案例代码请访问这里 zhang-glitch/cross-page-communication: 跨页面通信方案总结 (github.com))

总结

以上这八种方法梳理了常见的跨标签页面通信的过程,开发中一般对于同源页面使用LocalStorage + window.onstorage 监听BroadCast Channel这两种方式,对于非同源页面使用window.open + window.postMessage这种方式即可。其他方式了解即可。

其实这种通信方式有一些共性,indexedDB, cookie, localStorage方式,他们都是浏览器存储方式,同源页面可以获取到这些内容,因此就可以进行通信。service worker, shared worker, websocket他们都是通过一个中转人,通过接收消息,然后在进行消息分发。postMessage, BroadCast Channel他们就是通过js内置的消息通信方式进行通信。

往期年度总结

往期文章

专栏文章

结语

本篇文章到此就结束了,欢迎在评论区交流。

🔥如果此文对你有帮助的话,欢迎💗关注 、👍点赞 、⭐收藏✍️评论, 支持一下博主~

相关推荐
neter.asia1 分钟前
vue中如何关闭eslint检测?
前端·javascript·vue.js
~甲壳虫2 分钟前
说说webpack中常见的Plugin?解决了什么问题?
前端·webpack·node.js
光影少年21 分钟前
vue2与vue3的全局通信插件,如何实现自定义的插件
前端·javascript·vue.js
As977_22 分钟前
前端学习Day12 CSS盒子的定位(相对定位篇“附练习”)
前端·css·学习
susu108301891124 分钟前
vue3 css的样式如果background没有,如何覆盖有background的样式
前端·css
Ocean☾26 分钟前
前端基础-html-注册界面
前端·算法·html
Rattenking26 分钟前
React 源码学习01 ---- React.Children.map 的实现与应用
javascript·学习·react.js
Dragon Wu28 分钟前
前端 Canvas 绘画 总结
前端
CodeToGym33 分钟前
Webpack性能优化指南:从构建到部署的全方位策略
前端·webpack·性能优化
~甲壳虫34 分钟前
说说webpack中常见的Loader?解决了什么问题?
前端·webpack·node.js