window.postMessage() 方法可以安全地实现跨源通信。
iframe_contentWindow.postMessage(message, targetOrigin, [transfer]);
其他window可以监听分发的message:window.addEventListener("message", callback, false);
如果您不希望从其他网站接收message,请不要为message事件添加任何事件侦听器。 这是一个完全万无一失的方式来避免安全问题。
如果您确实希望从其他网站接收message,请始终使用origin和source属性验证发件人的身份。无法检查origin和source属性会导致跨站点脚本攻击。—— 任何窗口都可以向任何其他窗口发送消息,并且您不能保证未知发件人不会发送恶意消息。 但是,验证身份后,您仍然应该始终验证接收到的消息的语法。 否则,您信任只发送受信任邮件的网站中的安全漏洞可能会在您的网站中打开跨网站脚本漏洞。
使用postMessage将数据发送到其他窗口时,始终指定精确的目标origin,而不是*。
无法检查origin和source属性会导致跨站点脚本攻击。
Worker 接口是Web Workers API 的一部分,代表一个后台任务,创建一个专用Web worker,它只执行URL指定的脚本,并且在工作线程中执行。主从线程通过 postMessage发送消息和 onmessage onmessage 接受消息
worker 将运行在与当前 window不同的另一个全局上下文中,这个上下文由一个对象表示,标准情况下为DedicatedWorkerGlobalScope (标准 workers 由单个脚本使用; 共享workers使用SharedWorkerGlobalScope)。
除了无法读取DOM对象(包括:document、window、parent)、本地文件、对话框(alert/confirm/prompt),大部分 window 对象的方法和属性是可以使用的,如: WebSockets、IndexedDB、 XMLHttpRequest 等,具体查看 Functions and classes available to workers
SharedWorker
。Worker作用在《浏览器层面优化前端性能(1):Chrom组件与进程/线程模型分析》里面讲过
立即终止 Worker 的行为. 本方法并不会等待 worker 去完成它剩余的操作;worker 将会被立刻停止
Worker 接口的onmessage属性表示一个EventHandler事件处理函数,当message 事件发生时,该函数被调用。这些事件所属MessageEvent类型,且当Worker子线程返回一条消息时被调用
使用完毕,为了节省系统资源,必须关闭 Worker。
// 主线程
worker.terminate();
// Worker 线程
self.close();
主线程与 Worker 之间的通信内容,可以是文本,也可以是对象。需要注意的是,这种通信是拷贝关系,即是传值而不是传址,Worker 对通信内容的修改,不会影响到主线程。事实上,浏览器内部的运行机制是,先将通信内容串行化,然后把串行化后的字符串发给 Worker,后者再将它还原。这会造成性能问题!为了解决这个问题,JavaScript 允许主线程把二进制数据直接转移给子线程,但是一旦转移,主线程就无法再使用这些二进制数据了,这是为了防止出现多个线程同时修改数据的麻烦局面。这种转移数据的方法,叫做Transferable Objects。
var ab = new ArrayBuffer(1);
worker.postMessage(ab, [ab]);
对于大的数据处理,不会产生性能负担。
Worker 载入的是一个单独的 JavaScript 脚本文件,但是也可以载入与主线程在同一个网页的代码。减少网络加载耗时
<script id="worker" type="app/worker">
addEventListener('message', function () {
postMessage('some message');
}, false);
</script>
<script>
var blob = new Blob([document.querySelector('#worker').textContent]);
var url = window.URL.createObjectURL(blob);
var worker = new Worker(url);
worker.onmessage = function (e) {
// e.data === 'some message'
};
</script>
先将嵌入网页的脚本代码(注意必须指定<script>标签的type属性是一个浏览器不认识的值),转成一个二进制对象,然后为这个二进制对象生成 URL,再让 Worker 加载这个 URL。
worker 因为JavaScript 新开一个线程,执行worker代码。shareWoker因为不同tab(一个tab一个进程),因而新开一个进程。
// 主线程
let woker = new Worker('./test2.js');
woker.onmessage = (res) => {
console.log(res.data);
};
setTimeout(()=>{
console.log('main')
setTimeout(()=>{
console.log('main2')
setTimeout(()=>{
console.log('main3')
},0)
},0)
},0)
// woker 线程,test2.js
setTimeout(() => {
self.postMessage('woker1');
}, 0);
self.postMessage('woker2');
输出顺序为,每次都不一样,以为有网络请求呀
main main2 woker2 main3 woker1
main main2 woker2 woker1 main3
main main2 main3 woker2 woker1
如果是桶页面内,顺序就机会不会变
<script id="worker" type="app/worker">
setTimeout(() => {
self.postMessage('woker1');
}, 0);
self.postMessage('woker2');
</script>
<script>
// let woker = new Worker('./test2.js');
var blob = new Blob([document.querySelector('#worker').textContent]);
var url = window.URL.createObjectURL(blob);
var worker = new Worker(url);
worker.onmessage = (res) => {
console.log(res.data);
};
setTimeout(()=>{
console.log('main')
setTimeout(()=>{
console.log('main2')
setTimeout(()=>{
console.log('main3')
},0)
},0)
},0)
</script>
这个,还是JavaScript的 event loop 事件机制觉得,推荐阅读《弄懂javascript的执行机制:事件轮询|微任务和宏任务》
在浏览器环境中,常见的 macro task 有 setTimeout、MessageChannel、postMessage、setImmediate。而常见的 micro task 有 MutationObsever 和 Promise.then。需要留意的是:
Vue中对于 macro task 的实现,优先检测是否支持原生 setImmediate,这是一个高版本 IE 和 Edge 才支持的特性,不支持的话再去检测是否支持原生的MessageChannel,如果也不支持的话就会降级为 setTimeout 0。
MessageChannel创建了一个通信的管道,这个管道有两个端口[port1,port2],可以可以通过postMessage互相通信。
const channel = new MessageChannel();
let port1 = channel.port1;
let port2 = channel.port2;
port1.onmessage = function (event) {
console.log("port1收到来自port2的数据:" + event.data);
};
port2.onmessage = function (event) {
console.log("port2收到来自port1的数据:" + event.data);
};
port1.postMessage("发送给port2");
port2.postMessage("发送给port1");
MessageChannel用法很简单,但是功能却不可小觑。
多个web worker并想要在两个web worker之间实现通信的时候,MessageChannel就可以派上用场:
var w1 = new Worker("worker1.js");
var w2 = new Worker("worker2.js");
var ch = new MessageChannel();
w1.postMessage("initial port",[ch.port1]);
w2.postMessage("initial port",[ch.port2]);
w2.onmessage = function(e){
console.log(e.data);
}
通过web worker的postMessage方法把两个MessageChannel的port传递给两个web woker,然后就可以通过每个port的postMessage方法传递数据了。
传统iframe父子间通信:
var iframe1 = document.getElementById('iframe1');
iframe1.postMessage(message, '*');
使用MessagePort.postMessage方法把一条消息和MessageChannel.port2传递给iframe。
var iframe1 = document.getElementById('iframe1');
var iframe2 = document.getElementById('iframe2');
iframe1.contentWindow.postMessage('main','*',[port1]);
iframe2.contentWindow.postMessage('main','*',[port2]);
代码地址:channel messaging basic demo
nodejs的MessageChannel虽然与浏览器的,实现方式不同,但是用法相同,都是一个模型。在此列出,阐释这种思想。
const {isMainThread, parentPort, threadId, MessageChannel, Worker} = require('worker_threads');
Message事件的定义可参见这里
data | 包含任意字符串数据,由原始脚本发送 |
---|---|
origin | 一个字符串,包含原始文档的方案、域名以及端口(如:http://domain.example:80) |
lastEventId | 一个字符串,包含了当前的消息事件的唯一标识符。 |
source | 原始文件的窗口的引用。更确切地说,它是一个WindowProxy对象。 |
ports | 一个数组,包含任何MessagePort对象发送消息。 |
在跨文档通信和通道通信中,lastEventId的值一般是个空字符串;lastEventId应用在服务器端发送事件上。发送信息中如果没有ports, 则ports属性值就是个长度为0的数组。
MessageEvent继承DOM事件接口,且属性共享。然而,通信事件并没有冒泡,不能取消,也没有默认行为。
前端缓存 大致可以分为 http缓存 与 浏览器缓存
http缓存推荐阅读《浏览器http缓存机制剖析:存储策略与过期策略的机理分析》,我们来分析下 浏览器缓存
cookie、localStorage、sessionStorage
cookie 最大约为4k,每个域名最多50kcookie——不同浏览器限制不一样,一般用来存储关键数据(比如用户登录信息)
localStorage/sessionStorage通常有5MB的存储空间,比如微信文章 不需要改动的资源(如css/js)就基本存储在localStorage里面
推荐阅读《登录状态控制:cookies对比sessionStorage保持信息的分析》
WebSql和IndexDB,其中WebSql被规范废弃,他们都有大约50MB的最大容量,一般 当页面 store 的数据可以直接存储在里面。
已经被废弃,因为他的设计有些不合理的地方,他在缓存静态文件的同时,也会默认缓存html文件。这导致页面的更新只能通过manifest文件中的版本号来决定。所以,应用缓存只适合那种常年不变化的静态网站。如此的不方便,也是被废弃的重要原因。
推荐阅读《html5离线缓存manifest详解》、《HTML5离线存储实战之manifest的那些坑》
Service Worker本质上也是浏览器缓存资源用的,只不过他不仅仅是cache,也是通过worker的方式来进一步优化。
他基于h5的web worker,所以绝对不会阻碍当前js线程的执行,sw最重要的工作原理就是
这里不再赘述,再开一篇《ServiceWorker工作机制与生命周期:资源缓存与协作通信处理》
参考文章:
MessageChannel是什么,怎么使用? https://www.jianshu.com/p/4f07ef18b5d7
HTML5 postMessage iframe跨域web通信简介 https://www.zhangxinxu.com/wordpress/2012/02/html5-web-messaging-cross-document-messaging-channel-messaging/
Web Worker 使用教程 www.ruanyifeng.com/blog/2018/07/web-worker.html
转载本站文章《web messaging与Woker分类:漫谈postMessage跨线程跨页面通信》, 请注明出处:https://www.zhoulujun.cn/html/webfront/SGML/html5/2020_0615_8465.html
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。