浏览器多标签页通信

时间: 2019-03-05阅读: 274标签: 浏览器
浏览器多标签页通信有助于降低服务器负载,提高运营人员的工作效率,提高用户体验。是前端开发优化的一个重要环节。

需求来源

在多数CMS(内容管理系统)后台上,常见的是一个文章列表页面,点击列表项会打开一个新的文章详情页面。编辑人员经常在这个详情页面上对文章操作,比如修改标题、配图、摘要等内容。操作完毕之后,由于文章页和列表页是两个页面,文章内容数据不能及时同步到列表,这样就照成运营人员多次误操作,这大大降低了运营人员的工作效率。

对于前端工程师来讲,实现浏览器多个页卡之间的通信,及时更新相关数据更改,是一件重要的事情。

例如有一个需求:当文章详情页面更新的时候,会同步到文章列表页。


实现方式

方式一:cookie+setInterval

cookie最初是在客户端用于存储用户的会话信息的。由于HTTP是一种无状态的协议,服务器单从网络连接上无法知道客户身份。通过cookie就给客户端们颁发一个通行证,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个cookie。客户端浏览器会把cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该cookie一同提交给服务器。服务器检查该cookie,以此来辨认用户状态。服务器还可以根据需要修改cookie的内容。

在JavaScript中,cookie的操作接口即document.cookie,通过这个接口可以读取、写入、删除cookie。这个操作其实不太友好,所以很多工具库提供了cookie的操作方法。我这里提供一个简单的封装方法。

var QQ = {};
QQ.Cookie={
    set:function(name,value,expires,path,domain){
        if(typeof expires=="undefined"){
            expires=new Date(new Date().getTime()+3600*1000);
        }
        document.cookie=name+"="+escape(value)+((expires)?"; expires="+expires.toGMTString():"")+((path)?"; path="+path:"; path=/")+((domain)?";domain="+domain:"");
    },
    get:function(name){
        var arr=document.cookie.match(new RegExp("(^| )"+name+"=([^;]*)(;|$)"));
        if(arr!=null){
            return unescape(arr[2]);
        }
        return null;
    },
    clear:function(name,path,domain){
        if(this.get(name)){
            document.cookie=name+"="+((path)?"; path="+path:"; path=/")+((domain)?"; domain="+domain:"")+";expires=Fri, 02-Jan-1970 00:00:00 GMT";
        }
    }
};

 cookie有个特性,一个页面产生的cookie能被与这个页面的同一目录或者其他子目录下的页面访问,这样页面之间就产生了一个共享的存储空间。通常把cookie的path设置为一个更高级别的目录,比如默认“/”,从而使更多的页面共享cookie,实现多页面之间相互通信。 cookie所在的域,默认为请求的地址,也可以通过设置document.domain为父域等方式扩大cookie可被访问的域。


实现原理:

列表页通过setInterval定时器循环监听cookie的数据变动
列表页代码:

window.onload=function(){
    var tid =  '';
    setInterval(function(){    
        if(tid != QQ.Cookie.get("tid")){
            alert('数据更新!');
            tid = QQ.Cookie.get("tid")
        }
    }, 1000);
}

当详情页有数据修改时后,写入cookie
详情页代码:

<input id="content" type="text">
<button id="btn">Click</button>
<script>
    window.onload=function(){
        var oBtn=document.getElementById("btn");
        var oInput=document.getElementById("content");
        oBtn.onclick=function(){
            var val=oInput.value;
            QQ.Cookie.set("tid",val);
        } 
    }
</script>

cookie+setInterval的不足

1、cookie空间有限,浏览器在每一个域名下最多能设置30-50个cookie,容量最多4K左右。
2、每次HTTP请求会把当前域的cookie发送到服务器上,而有些cookie只是浏览器才用的到,浪费网络带宽。
3、setInterval的频率设置,过大会影响浏览器性能,过小会影响时效性。

cookie+setInterval的优点:

兼容性好,几乎所有的浏览器都支持。


方式二:localStorage

在HTML5中,新加入了一个localStorage特性,这个特性主要是用来作为本地存储来使用的,解决了cookie存储空间不足的问题,localStorage中一般浏览器支持的是5M大小,这个在不同的浏览器中localStorage会有所不同。
localStorage的API也很简单,提供了JS的读写操作。

if(!window.localStorage){
    alert("浏览器不支持localstorage");
    return false;
}else{
    var storage = window.localStorage;
    //通过属性写入a字段
    storage.a = 1;
    //通过方法写入b字段
    storage.setItem("b",2);

    storage.getItem("a");
    storage.b;
    storage.clear();
}

 它还比cookie多了一个优点,提供了onstorage以及storage事件,可以绑定一个回调函数,使用如下:

window.onstorage = function(e){console.log(e)}
// 或者
window.addEventListener('storage', function(){ console.log(e)})

localStorage是Storage对象的实例。对Storage对象进行任何修改,都会在触发storage事件。当通过属性或者setItem()方法保存数据,或者使用delete操作符或removeItem()删除数据,或者调用clear()方法时,都会触发该事件。通过这个事件,我们可以实现页卡之间的变动监听。


实现原理:

列表页通过storage监听localStorage的数据变动
列表页代码:

<script>
    window.addEventListener("storage",function(event){
        console.log("newValue is"+localStorage.getItem("tid"));
        console.log("oldValue is"+event.oldValue);
        window.alert('数据更新!');
    },false);    
</script>

当详情页有数据修改时后,写入localStorage
详情页代码:

<input id="content" type="text"/>
<button id="btn">Click</button>
<script>
    window.onload=function(){
        var oBtn=document.getElementById("btn");
        var oInput=document.getElementById("content");
        oBtn.onclick=function(){
            var val=oInput.value;
            localStorage.setItem("tid",val);
        }
    }
</script>

不过,onstorage以及storage事件,针对都是非当前页面对localStorage进行修改时才会触发,当前页面修改localStorage不会触发监听函数。还有就是在对原有的数据的值进行修改时才会触发,比如原本已经有一个key为a,值为1的localStorage,再执行:localStorage.setItem('a', 1)代码,同样是不会触发监听函数的。

localStorage的不足

1、浏览器的容量大小不统一(比cookie大很多了),并且在高版本的浏览器才支持localStorage这个属性
2、目前所有的浏览器中都会把localStorage的值类型限定为string类型,需要JSON转换。
3、localStorage本质上是对字符串的读取,如果存储内容多的话会消耗内存空间,会导致页面变卡。
4、localStorage只能监听非己页面的数据变化,这一点严重影响使用。

localStorage的优点

1、解决了cookie容量小和时效性不足的问题。


方式三:WebSocket

WebSocket API是下一代客户端--服务器的异步通信方法,已被W3C进行了标准化。WebSocket API最伟大之处在于服务器和客户端可以双向实时通信。WebSocket并不限于以Ajax(或XHR)方式通信,因为Ajax技术需要客户端发起请求,而WebSocket服务器和客户端可以彼此相互推送信息;XHR受到域的限制,而WebSocket允许跨域通信。

它的使用很简单,如下:

// 创建一个Socket实例
var socket = new WebSocket('ws://localhost:8080'); 

// 打开Socket 
socket.onopen = function(event) { 
    // 发送一个初始化消息
    socket.send('I am the client and I\'m listening!'); 
    // 监听消息
    socket.onmessage = function(event) { 
        console.log('Client received a message',event); 
    }; 
    // 监听Socket的关闭
    socket.onclose = function(event) { 
        console.log('Client notified socket has closed',event); 
    }; 
    // 关闭Socket.... 
    socket.close() 
};

WebSocket提供了send方法和onmessage事件,用来发送和接收数据。onmessage事件提供了一个data属性,它可以包含消息的Body部分。消息的Body部分必须是一个字符串,可以进行序列化/反序列化操作,以便传递更多的数据。


实现原理:

列表页通过onmessage监听socket服务器发送过来的消息
列表页代码:

<script>
    var socket = new WebSocket('ws://localhost:8080'); 
    socket.onopen = function(event) { 
        socket.onmessage = function(event) { 
            console.log('Client received a message', event); 
        };
    };  
</script>

当详情页有数据修改时后,通过socket连接,通知列表页更新数据。
详情页代码:

<input id="content" type="text"/>
<button id="btn">Click</button>
<script>
    var socket = new WebSocket('ws://localhost:8080'); 
    window.onload=function(){
        var oBtn=document.getElementById("btn");
        var oInput=document.getElementById("content");
        oBtn.onclick=function(){
            var val=oInput.value;
            socket.onopen = function(event) {
                // 发送数据类型必须是string、ArrayBuffer、Blob之一
                socket.send('数据更新!'); 
            }
    }
</script>

WebSocket的语法非常简单,不过需要IE10+浏览器才支持WebSocket通信。如果你的业务需要兼容IE8,9。业界通常使用第三方库来解决这个问题,比如Socket.IO,它使用检测功能来判断是否建立WebSocket连接,或者是AJAX long-polling连接,或Flash等,可快速创建实时的应用程序。Socket.IO还提供了一个NodeJS API,它看起来非常像浏览器的API。

WebSocket的不足:

1、它需要服务端的支持才能完成任务。如果socket数据量比较大的话,会严重消耗服务器的资源。

WebSocket的优点:

1、使用简单,功能灵活、强大,如果部署了WebSocket服务器,可以实现很多实时的功能。


方式四:BroadcastChannel

BroadcastChannel即广播频道,是window下面的一个API,该API是用于同源不同页面之间完成通信的功能。我们可以理解它是一个广播台,所有的广播实例,都会接入这个广播台(中介者模式中的控制中心),所以,只要在初始化实例时,传入相同的频道值,就会被接入到一个相同的广播频道中。它的实现最简单,很多第三方JS库都实现了一套自己的BroadcastChannel。


实现原理:

列表页通过onmessage监听其他页面发送过来的消息
列表页代码:

// 接收广播
let articleCast = new BroadcastChannel('mychannel');
articleCast.onmessage = function (e) {
    console.log(e.data);
}

当详情页有数据修改时后,通过postMessage,传递数据。
详情页代码:

// 创建广播并发送
let listCast = new BroadcastChannel('mychannel'); 
myObj = { tid: "123", title: "更改后的标题" };
listCast.postMessage(myObj);

BroadcastChannel的不足:

1、兼容性极差,只支持最新版的Chrome和Firefox,完全不支持IE和Safari。

BroadcastChannel的优点:

1、使用简单,功能单一,跨页面通信的理想选择。


方式五:SharedWorker

SharedWorker也是HTML5提供的新的浏览器API,叫共享工作线程。它允许多个页面共享使用线程,每个页面都链接到该共享工作线程的某个端口号上。页面通过该端口与共享工作线程进行通信。目前的Web所有程序的操作都基于页面的,而SharedWorker的引入开辟了一个“Web程序”在后台线程的概念。而且它还可以和页面交互,相当于把所有页面都聚拢起来了。上例讲为每个页面都维护一份WebSocket代码不仅耗费大量的连接数,而且还拖慢性能。这些通用的连接最好当然做成可跨域页面共用的,在SharedWorker引入之前并没有一个完美的跨页面通信解决方案。


实现原理

列表页通过onmessage监听SharedWoker发送过来的消息
列表页代码:

<script>
    var s = new SharedWorker('x.js');
    s.port.onmessage = function(e){
        console.log(e.data);
        window.alert("数据变化!")
    };
    s.port.start();
</script>

当详情页有数据修改时后,通过SharedWorker,通知列表页更新数据。

<input id="content" /><input type="button" id="btn" value="发送" />
<script>
    var s = new SharedWorker('x.js');
    btn.onclick=function(){
        s.port.postMessage(document.getElementById('content').value);
    };
    s.port.start();
</script>

 其中共享线程x.js的代码也很简单,它的工作是双向的,每一个页面都可以用来接收和发送数据。

//x.js
var pool = [];
onconnect = function(e) {
    pool.push(e.ports[0]);
    e.ports[0].onmessage = function(e){
        for(var i=0; i<pool.length; i++)
        pool[i].postMessage(e.data);
    };
};

 SharedWorker就像运行在浏览器后端的守卫者,可以被多个window同时使用,但必须保证这些标签页都是同源的(相同的协议,主机和端口号)。

SharedWorker的不足:

1、兼容性较差,IE完全不支持,chrome和Firefox支持很完善,Safari部分支持,如果你的业务是内部系统,不考虑IE,可以使用。
2、API比较简单,配置繁琐,使用起来还是比较麻烦。

SharedWorker的优点:

1、功能强大,不限于浏览器通信,还有共享数据,方法等功能。由于是另启的一个新线程,不影响主线程代码业务,性能优秀,无需借助服务器,是一个完美的跨页面通信解决方案。

我们做了什么?(划重点)

SharedWorker提供的API很少,使用比较简单,如果需要完成复杂的页面通信,还是有一定难度。基于此,我实现了一款基于SharedWorker的封装库,叫作superSharedWorker

它是一款页面之间通信的JavaScript框架,它通过shared worker 实现纯浏览器页卡之间的通信。你无需了解shared worker,可以快速使用页面之间的数据传递,快捷,强大。它的优点就是通过原生JS实现,无需依赖任何JS库实现了对sharedWorker的封装。开箱即用,配置简单。

两种使用方式:
1、ES6 import的方式

import superSharedWorker from './src/index.js';
let superSharedWorker = new superSharedWorker('page1', callback); //注册
superSharedWorker.send('hello world!'); //发送消息

2、script标签外链的形式

<script src="./build/super-sharedworker.js"></script>
<script type="text/javascript">
    //<!--
        var superSharedWorker = new SuperShared('page1', onRecvMsg);
        function onRecvMsg(message) {
           console.log(message)
        }
        superSharedWorker.send('hello, world');
    //-->
</script>

更多用法举例:

let superSharedWorker = new superSharedWorker('page1', callback); //注册
superSharedWorker.add({name:'chunpengliu', sex:1});
superSharedWorker.del('sex');// 删除缓冲区数据
superSharedWorker.send({'time':2019}, 'page2'); //一次性发送缓冲区数据,只发送给name="page2"的页面
superSharedWorker.close(); //关闭线程,节省资源

它提供了很多强大的功能,可一对一,一对多发送消息。像使用git一样传递数据。


小结

通过讨论,实现了四种实现浏览器标签页之间的通信,分别是使用cookie、使用websocket协议、通过localstorage、以及使用html5浏览器的新特性SharedWorker,每种方法各有利弊。如果不考虑兼容旧的浏览器,superSharedWorker 或许是最好的解决方案,优化使用效率,提升用户体验,赶快使用浏览器多标签页通信功能吧!

来自:https://segmentfault.com/a/1190000018386033


链接: http://www.fly63.com/article/detial/2227

不同浏览器的内核

网页上所用到的语言有:html, css, JavaScript等,其中,前两者通常决定了该页面长什么样,它们是可以说都是约定的规范。不同的浏览器在获取到某页面的代码文件后,负责根据这套规范将代码渲染出来呈现给用户

Js实现阻止浏览器返回的功能

无论pc端还是移动端,浏览器都会带有后退按钮或后退键.主要方便我们能返回以前访问过的页面,但有时候我们不得不关闭这个功能.尤其是对于一些推广落地页,用户进入后不希望它返回

完美解决安卓端百度浏览器屏蔽fixed悬浮元素的问题

h5活动页面底部有个悬浮图片按钮,使用fixed悬浮定位在底部,但是在安卓端的百度浏览器下打开,却发现该图片一闪而过,在百度浏览器中消失不见。

浏览器的三种Js弹窗方式

在做网页时,常常使用弹窗,以上就是浏览器的三种弹窗方式, alert 在测试时常用; confirm 可以套用if...else 来用 ,比如 :confirm点击了确定做什么事情,点击了取消又做什么事情;prompt 弹窗输入 ; 可以给网页设置密码。

火狐浏览器 访问所有HTTPS网站显示连接不安全解决办法

当 Firefox 连接到一个安全的网站时(网址最开始为“https://”),它必须确认该网站出具的证书有效且使用足够高的加密强度。如果证书无法通过验证,或加密强度过低,Firefox 会中止连接到这个网站,并显示“连接不安全”的错误信息页面。

GeckoView:Mozilla面向移动浏览器打造的渲染引擎

Mozilla 现已推出面向 Android 的全新移动浏览器 Firefox Preview。与大多数浏览器所采用的 Bink 渲染引擎不同,Firefox Preview 的渲染引擎 GeckoView 由 Mozilla 自行开发

常用浏览器内核及分类

浏览器是网页运行的平台,常用的浏览器有 IE、火狐(Firefox)、谷歌(Chrome)、Safari和Opera等。我们平时称为五大浏览器。 浏览器内核分成两部分:渲染引擎和 JS 引擎

理解Js中的Repaint和Reflow

最近,在研究React的虚拟DOM如此之快的原因时,我意识到我们对javascript性能的了解甚少。所以我写这篇文章是为了帮助提高对Repaint和Reflow以及JavaScript性能的认识。

用Vue.js在浏览器中裁剪图像

你是否写了一个需要接受用户上传图片的 Web 应用,后来才意识到用户总是提供各种形状和大小的图像来破坏你的网站主题?在网络上处理图像很容易成为一种痛苦 —— 当然,除非你使用了正确的工具。

防止用户在浏览器下调试查看js代码

浏览器可以通过F12或者鼠标右键的形式打开html页面,然后就可以看到页面的的信息,如dom结构,加载文件、请求信息等。那有没有办法禁止掉这一行为呢?

fly63.com版权所有,内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权,请与小编联系!情况属实本人将予以删除!

广告赞助文章投稿关于web前端网站点搜索站长推荐网站地图站长QQ:522607023

小程序专栏: 土味情话心理测试脑筋急转弯幽默笑话段子句子语录成语大全