html5中sharedWorker实现多页面通信的示例代码


Posted in Javascript onMay 07, 2021

是这样的,今天玩github,先是在没有登录浏览了一些页面,然后在某一页面进行了登录。这时再切换的其他页面时就看到了下面的提示:

html5中sharedWorker实现多页面通信的示例代码

那么这是怎么做到的呢?我们可以想到,一种办法是 localStorage,在某一个页面登录时,修改localStorage 状态,其他页面在显示的时候,读取最新的状态,然后显示提示:

// 登录的页面
localStorage.setItem('login', true);
 
// 其他页面
document.addEventListener("visibilitychange", function() {
    if (localStorage.setItem('login') === 'true') {
        alert('你已登录,请刷新页面');
    }
}

html5中sharedWorker实现多页面通信的示例代码

然而,github并没有这么做,localStorage里也找不到相关的字段,一番查找之后,发现他们是用 sharedWorker 实现的。那我们就来了解下sharedworker

什么是sharedWorker

sharedWorker 顾名思义,是 worker 的一种,可以由所有同源的页面共享。同Worker的api一样,传入js的url,就可以注册一个 sharedWorker 实例:

let myWorker = new SharedWorker('worker.js');

接下来,我们看一下具体是 worker 和页面之间是如何发送和接收消息的。但是与普通 Worker 不同的是:
1 同一个js url 只会创建一个 sharedWorker,其他页面再使用同样的url创建sharedWorker,会复用已创建的 worker,这个worker由那几个页面共享。
2 sharedWorker通过port来发送和接收消息

messagePort

假设我们有两个js,一个是跑在页面里的 page.js,另一个是跑在 worker里的 worker.js。那么我们要在 page.js 里注册一个 sharedWorker,代码如下:

// page.js
let myWorker = new SharedWorker('worker.js');
// page通过worker port发送消息
myWorker.port.postMessage('哼哼');
// page通过worker port接收消息
myWorker.port.onmessage = (e) => console.log(e.data);
 
// worker.js
onconnect= function(e) {
    const port = e.ports[0];
    port.postMessage('哈嘿');
    port.onmessage = (e) => {
        console.log(e.data);
    }
}

调试sharedWorker

在上面的例子中,我们在worker中使用了console.log来打印来自页面的message,那么到哪里可以看到打印的log呢?我们可以在浏览器地址栏里面输入 `chrome://inspect,然后在侧边栏选中shared workers了,就可以看到浏览器,目前在运行的所有worker。点击inspect会打开一个开发者工具,然后就可以看到输出的log了。

html5中sharedWorker实现多页面通信的示例代码

这里我们看到我们的worker名字是untitled,那是因为sharedworker 构造函数还支持传入第二个参数作为名字:

let myWorker = new SharedWorker('worker.js', 'awesome worker');

回到文章一开始的例子,我们前面实现了页面和worker之间的通信,那么该如何让worker向多个页面发送消息呢?一个思路就是我们把port缓存起来,作为一个port pool,这样当我们需要向所有页面广播消息的时候,就可以遍历port,然后发送消息:多页面发布消息

// worker js
const portPool = [];
onconnect= function(e) {
    const port = e.ports[0];
    // 在connect时将 port添加到 portPool中
    portPool.push(port);
    port.postMessage('哈嘿');
    port.onmessage = (e) => {
        console.log(e.data);
    }
}
 
function boardcast(message) {
    portPool.forEach(port => {
        port.portMessage(port);
    })
}

这样我们就基本实现了向多个页面广播消息的功能。

清除无效的port

上面的实现中有一个问题,就是在页面关闭后,workerPool中的port并不会自动清除,造成内存的白白浪费。我们可以在页面关闭前通知shared worker页面将要关闭,然后让worker将无效的 messagePort 从 portPool 中移除。

// 页面
window.onbeforeunload = () => {
  myWorker.port.postMessage('TO BE CLOSED');
};
 
// worker.js
const portPool = [];
onconnect = function(e) {
  var port = e.ports[0];
  portPool.push(port);
  port.onmessage = function(e) {
    console.log(e);
    if (e.data === 'TO BE CLOSED') {
      const index = ports.findIndex(p => p === port);
      portPool.splice(index, 1);
    }
    var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
    port.postMessage(workerResult);
  }
}
 
function boardcast(message) {
    portPool.forEach(port => {
        port.portMessage(port);
    })
}

这样,我们就实现了一个简单的多页面广播的sharedWorker。我们可以用它来广播一下时间:

参考

https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker/SharedWorker
https://github.com/mdn/simple-shared-worker

到此这篇关于html5中sharedWorker实现多页面通信的示例代码的文章就介绍到这了

Javascript 相关文章推荐
jquery下实现overlay遮罩层代码
Aug 25 Javascript
基于jquery的获取浏览器窗口大小的代码
Mar 28 Javascript
JavaScript中的无阻塞加载性能优化方案
Oct 10 Javascript
javascript实现日期按月份加减
May 15 Javascript
浏览器环境下JavaScript脚本加载与执行探析之动态脚本与Ajax脚本注入
Jan 19 Javascript
JavaScript头像上传插件源码分享
Mar 29 Javascript
Vuejs第六篇之Vuejs与form元素实例解析
Sep 05 Javascript
利用浮层使select不可选的实现方法
Dec 03 Javascript
[js高手之路]原型式继承与寄生式继承详解
Aug 28 Javascript
Servlet返回的数据js解析2种方法
Dec 12 Javascript
基于Echarts图表在div动态切换时不显示的解决方式
Jul 20 Javascript
Vue路由 重定向和别名的区别说明
Sep 09 Javascript
详解如何使用Node.js实现热重载页面
May 06 #Javascript
关于Vue Router的10条高级技巧总结
May 06 #Vue.js
在JavaScript中如何使用宏详解
May 06 #Javascript
如何用JS实现简单的数据监听
May 06 #Javascript
详解TS数字分隔符和更严格的类属性检查
May 06 #Javascript
JS中一些高效的魔法运算符总结
May 06 #Javascript
react国际化react-intl的使用
You might like
php递归删除目录下的文件但保留的实例分享
2014/05/10 PHP
php的慢速日志引起的Mysql错误问题分析
2014/05/13 PHP
JSON 数据格式介绍
2012/01/13 Javascript
onbeforeunload与onunload事件异同点总结
2013/06/24 Javascript
JavaScript获取table中某一列的值的方法
2014/05/06 Javascript
JavaScript学习笔记之Function对象
2015/01/22 Javascript
jQuery中DOM操作实例分析
2015/01/23 Javascript
jQuery实现的指纹扫描效果实例(附演示与demo源码下载)
2016/01/26 Javascript
AngularJS中比较两个数组是否相同
2016/08/24 Javascript
js获取元素的标签名实现方法
2016/10/08 Javascript
nodejs根据ip数组在百度地图中进行定位
2017/03/06 NodeJs
JavaScript满天星导航栏实现方法
2018/03/08 Javascript
AngularJS对动态增加的DOM实现ng-keyup事件示例
2018/03/12 Javascript
BootStrap中的模态框(modal,弹出层)功能示例代码
2018/11/02 Javascript
Vue3.0数据响应式原理详解
2019/10/09 Javascript
微信小程序 wx.getUserInfo引导用户授权问题实例分析
2020/03/09 Javascript
Python的SQLAlchemy框架使用入门
2015/04/29 Python
python+opencv实现的简单人脸识别代码示例
2017/11/14 Python
在Mac下使用python实现简单的目录树展示方法
2018/11/01 Python
分享8个非常流行的 Python 可视化工具包
2019/06/05 Python
pyqt5中QThread在使用时出现重复emit的实例
2019/06/21 Python
Python 利用高德地图api实现经纬度与地址的批量转换
2019/08/14 Python
使用python实现回文数的四种方法小结
2019/11/24 Python
Tkinter中复选菜单是否被选中的判断与设置方式
2020/03/04 Python
使用opencv识别图像红色区域,并输出红色区域中心点坐标
2020/06/02 Python
美国美妆网站:B-Glowing
2016/10/12 全球购物
加拿大鞋网:Globo Shoes
2019/12/26 全球购物
法国在线药房:DoctiPharma
2020/10/21 全球购物
Oracle中delete,truncate和drop的区别
2016/05/05 面试题
小学生自我鉴定
2013/10/12 职场文书
致跳远运动员加油稿
2014/02/11 职场文书
服装发布会策划方案
2014/05/22 职场文书
运动会广播稿100字
2014/09/14 职场文书
教师调动申请报告
2015/05/18 职场文书
汶川大地震感悟
2015/08/10 职场文书
运动会100米广播稿
2015/08/19 职场文书