浏览器多标签页通信

栏目: JavaScript · 发布时间: 5年前

内容简介:浏览器多标签页通信有助于降低服务器负载,提高运营人员的工作效率,提高用户体验。是前端开发优化的一个重要环节。在多数CMS(内容管理系统)后台上,常见的是一个文章列表页面,点击列表项会打开一个新的文章详情页面。编辑人员经常在这个详情页面上对文章操作,比如修改标题、配图、摘要等内容。操作完毕之后,由于文章页和列表页是两个页面,文章内容数据不能及时同步到列表,这样就照成运营人员多次误操作,这大大降低了运营人员的工作效率。对于前端工程师来讲,实现浏览器多个页卡之间的通信,及时更新相关数据更改,是一件重要的事情。

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

需求来源

在多数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 或许是最好的解决方案,优化使用效率,提升用户体验,赶快使用浏览器多标签页通信功能吧!


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Head First HTML5 Programming

Head First HTML5 Programming

Eric Freeman、Elisabeth Robson / O'Reilly Media / 2011-10-18 / USD 49.99

What can HTML5 do for you? If you're a web developer looking to use this new version of HTML, you might be wondering how much has really changed. Head First HTML5 Programming introduces the key featur......一起来看看 《Head First HTML5 Programming》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具