今天面试遇到的问题,当时只想到了使用localStorage,后来查了资料,还有其他的几种:如使用cookie+setInterval()、使用websocket协议、使用html5浏览器的新特性SharedWorker。在此记录巩固。
使用localStorage
- localStorage是浏览器多个标签共用的存储空间,所以可以用来实现多标签之间的通信(ps:sessionStorage是会话级的存储空间,每个标签页都是单独的)。
- 在一个标签页里面使用 localStorage.setItem(key, value) 添加(修改、删除)内容;
在另一个标签页里面监听 storage事件。
即可得到 localStorage存储的值,实现不同标签页之间的通信。
window.onstorage = (e) => {console.log(e)}
// 或者这样
window.addEventListener('storage', (e) => console.log(e))
cookie+setInterval()
将要传递的信息存储在cookie中,每隔一定时间读取cookie信息,即可随时获取要传递的信息。
页签1:
<input type="text" id="ipt">
<input type="button" id="btn" value="提交">
<script type="text/javascript">
$(function(){
$("#btn").click(function(){
var ipt=$("#ipt").val();
document.cookie="name="+ipt;
});
});
</script>
页签2:
<script type="text/javascript">
$(function(){
function getCookie(key) {
return JSON.parse("{\"" + document.cookie.replace(/;\s+/gim,"\",\"").replace(/=/gim, "\":\"") + "\"}")[key];
}
setInterval(function(){
console.log("name=" + getCookie("name"));
}, 10000);
});
</script>
webworker
- 我们都知道JavaScript是单线程的,但是浏览器是拥有过个线程的比如:gui渲染线程、JS引擎线程、事件触发线程、异步http请求线程。
- webworker作为浏览器的一个新特性,可以提供一个额外的线程来执行一些js代码,并且不会影响到浏览器用户界面。
- 应用场景:比如页面中包含耗时较大的算法代码时,就会阻塞线程影响浏览器渲染等等。这时候就可把耗时代码,放到webworker(另一个线程)中执行。
- 注意,这种多线程能力不是JavaScript语言原生具有的,而是浏览器宿主环境提供的。
- 普通的webworker直接使用
new Worker()
即可创建,这种webworker是当前页面专有的。然后还有种共享worker(SharedWorker),这种是可以多个标签页、iframe共同使用的,接下来介绍如何使用SharedWorker实现标签页之间的通信。
SharedWorker
- SharedWorker可以被多个window共同使用,但必须保证这些标签页都是同源的(相同的协议,主机和端口号)
- 首先新建一个js文件
worker.js
,具体代码如下:
// sharedWorker所要用到的js文件,不必打包到项目中,直接放到服务器即可
let data = ''
onconnect = function (e) {
let port = e.ports[0]
port.onmessage = function (e) {
if (e.data === 'get') {
port.postMessage(data)
} else {
data = e.data
}
}
}
- webworker端(暂且这样称呼)的代码就如上,只需注册一个onmessage监听信息的事件,客户端(即使用sharedWorker的标签页)发送message时就会触发。
- 注意webworker无法在本地使用,出于浏览器本身的安全机制,所以我这次的示例也是放在服务器上的,
worker.js
和index.html
在同一目录。 - 因为客户端和webworker端的通信不像websocket那样是全双工的,所以客户端发送数据和接收数据要分成两步来处理。示例中会有两个按钮,分别对应的向sharedWorker发送数据的请求以及获取数据的请求,但他们本质上都是相同的事件--发送消息。
- webworker端会进行判断,传递的数据为'get'时,就把变量data的值回传给客户端,其他情况,则把客户端传递过来的数据存储到data变量中。下面是客户端的代码:
// 这段代码是必须的,打开页面后注册SharedWorker,显示指定worker.port.start()方法建立与worker间的连接
if (typeof Worker === "undefined") {
alert('当前浏览器不支持webworker')
} else {
let worker = new SharedWorker('worker.js')
worker.port.addEventListener('message', (e) => {
console.log('来自worker的数据:', e.data)
}, false)
worker.port.start()
window.worker = worker
}
// 获取和发送消息都是调用postMessage方法,我这里约定的是传递'get'表示获取数据。
window.worker.port.postMessage('get')
window.worker.port.postMessage('发送信息给worker')
- 页面A发送数据给worker,然后打开页面B,调用
window.worker.port.postMessage('get')
,即可收到页面A发送给worker的数据。