当前位置: 首页 > Web前端 > JavaScript

浅谈MessageChannel

时间:2023-03-27 17:18:19 JavaScript

什么是MessageChannelMessageChannel允许两个不同的脚本运行在同一个文档的不同浏览器上下文中(比如两个iframe,documentbody和一个iframe,两个文档使用SharedWorker,或者两个worker)直接通信,使用一个两端的端口通过双向通道相互传递消息。MessageChannel以DOMEvent的形式发送消息,因此是一个异步的宏任务。基本用法使用MessageChannel()构造函数创建一个通信通道,获取两个端口MessagePort对象port1port2;一个端口使用postMessage发送消息,另一个端口通过onmessage接收消息;对方端口通过onmessage接收消息;反序列化消息时,使用onmessageerror处理;停止发送消息时,调用close关闭端口;方法1const{port1,port2}=newMessageChannel();port1.onmessage=(event)=>{console.log('从port2收到消息:',event.data);};port1.onmessageerror=(event)=>{};port2.onmessage=function(event){console.log('从端口1收到消息:',event.data);port2.postMessage('我是port2');};port2.onmessageerror=(event)=>{};port1.postMessage('我是port1');方法二const{port1,port2}=newMessageChannel();port1.addEventListener('message',event=>{console.log('Receivedmessagefromport2:',event.data);});port1.addEventListener('messageerror',(event)=>{});port1.start();port2.addEventListener('message',event=>{console.log('从port1收到消息:',event.data);port2.postMessage('Iisport2');});port2.addEventListener('messageerror',(event)=>{});port2.start();port1.postMessage('我是port1');以上两个方法的输出是:Receivedmessagefromport1:Iamport1Receivedmessagefromport2:Iamport2使用addEventListener方法,需要手动调用start()方法消息可以流,因为初始化时挂起的onmessage已隐式调用start()方法。EventLoop中的执行顺序同步任务>微任务>requestAnimationFrame>DOM渲染>宏任务setTimeout(()=>{console.log('setTimeout')},0)const{port1,port2}=newMessageChannel()port2.onmessage=e=>{console.log(e.data)}port1.postMessage('MessageChannel')requestAnimationFrame(()=>{console.log('requestAnimationFrame')})Promise.resolve().then(()=>{console.log('Promise1')})输出是:Promise//microtask执行requestAnimationFramesetTimeout//macrotask,先定义并执行MessageChannel//macrotask,然后定义并执行requestAnimationFrame-不是macrotask任务window.requestAnimationFrame()告诉浏览器表示要执行一个动画,并要求浏览器在下次重绘前调用指定的回调函数来更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下次重绘之前执行---严格意义上的MDN,raf不是宏任务,因为执行时机完全与宏任务不一致;raf任务队列执行时,会执行此刻队列中的所有任务;使用场景一:同一个文档的上下文通信varchannel=newMessageChannel();varpara=document.querySelector('p');varifr=document.querySelector('iframe');varotherWindow=ifr.contentWindow;ifr.addEventListener("load",iframeLoaded,false);functioniframeLoaded(){otherWindow.postMessage('来自主页的问候!','*',[channel.port2]);}channel.port1.onmessage=handleMessage;functionhandleMessage(e){para.innerHTML=e.data;}2:结合WebWorker实现多线程通信3:最深拷贝需求对于深拷贝场景,使用JSON.parse(JSON.stringify(object))。但是这种方法忽略了未定义、函数、符号和循环引用的对象。//深拷贝函数functiondeepClone(val){returnnewPromise(resolve=>{const{port1,port2}=newMessageChannel()port2.onmessage=e=>resolve(e.data)port1.postMessage(val)})}使用MessageChannel实现的深拷贝只能解决未定义和循环引用对象的问题,但是对于Symbol和function还是束手无策。实际问题描述:有两个方法被第三方调用,顺序不定。调用这两个方法后,再进行进一步的处理。解决方法是用setTimeout模拟方法的调用顺序,代码如下:const{port1,port2}=newMessageChannel()letdataconsthandleUser=newData=>{if(data){constresult={...data,...newData}console.log('获取所有数据',result)port1.close()port2.close()}else{data=newData}}constgetName=()=>{constparams={name:'123'}port1.postMessage(params)port1.onmessage=e=>{handleUser(e.data)}}constgetAge=()=>{constparams={age:88}port2.postMessage(params)port2.onmessage=e=>{handleUser(e.data)}}setTimeout(()=>{getName()},0)setTimeout(()=>{getAge()},10)

最新推荐
猜你喜欢