前端技术中的常用通信方案


 

 
  原生js通信
1. Event:
  在发送方注册事件,并在接收方监听该事件来进行通信。发送方在适当的时机触发事件,接收方收到事件后执行相应的处理 event
-example <body> <div id="wrap"> <button id="message">发送消息</button> <div id="receiver"></div> </div> <script> // 事件名称 const eventName = 'messageEvent'; // 发送方 const sendButton = document.getElementById('message'); // 接收方 const receiverElement = document.getElementById('receiver'); // 定义自定义事件 const customEvent = new Event(eventName); // 定义事件派发函数 function dispatchCustomEvent(e) { receiverElement.dispatchEvent(customEvent); } // 在发送按钮点击时调用事件派发函数 sendButton.addEventListener('click', dispatchCustomEvent); // 监听自定义事件 receiverElement.addEventListener(eventName, function(event) { // 收到事件后执行相应处理 console.log('接收到事件',event.type); }); </script> </body> 2.iframe

    父页面监听iframe消息:

      window.addEventListener('message', receiveMessageIframePage, false);

    父页面发送给iframe页面的消息:

      iframe.contentWindow.postMessage({ type: 'boundFileKeys', data: "消息内容体" }, '*');

    iframe页面监听父页面发过来的消息:

      window.addEventListener('message', onMessage, false);

    iframe页面给父页面发送消息 

       window.parent.postMessage({ type: 'check', data: ["自定义需要发送的数据"] }, '*');


3.标签通信–频道
    BroadcastChannel 接口代理了一个命名频道,可以让指定 origin 下的任意 browsing context 来订阅它。它允许同源的不同浏览器窗口,Tab 页,frame 或者 iframe 下的不同文档之间相互通信。通过触发一个 message 事件,消息可以广播到所有监听了该频道的 BroadcastChannel 对象
    channel1
    channel2

      function BroadChannel(cb){
                // 获取频道
                this.get = function(channelname){
                    return this.channelMap.get(channelname)
                }
                // 获取默认频道名称
                this.getDefaultName  = function(){
                    return 'broad-channel-' + (this.channelMap.size + 1)
                }
                // 获取所有频道数
                this.getLength  = function(){
                    return this.channelMap.size
                }
                // 创建频道
                this.create = function(channelname){
                    const self = this
                    const name = channelname || self.getDefaultName()
                    const channel = new BroadcastChannel(name)
                    channel.onmessage = function(ev){
                        const message = {
                            data: ev.data,
                            name,
                            time: Date.now()
                        }
                        cb && cb(message)
                    }
                    channel.onmessageerror = function(ev){
                        console.error(ev.data);
                    }
                    self.channelMap.set(name,channel)
                    self.channelLength = self.getLength()
                    return channel
                }
                // 开通频道
                this.open = function (channelname){
                    const channel = this.get(channelname)
                    return channel || this.create(channelname)
                }
                // 关闭频道
                this.close = function(channelname){
                    const channel = this.get(channelname)
                    if( channel ){
                        channel.close()
                    }
                }
                // 删除频道
                this.delete = function(channelname){
                    this.close(channelname)
                    this.channelMap.delete(channelname)
                    this.channelLength = this.getLength()
                }
                // 判断是否存在相同频道
                this.has = function(channelname){
                    return this.channelMap.has(channelname)
                }
                // 发送消息
                this.postMessage = function(channelname, data){
                    const channel = this.get(channelname)
                    if( channel ){
                        try {
                            // 正常
                            channel.postMessage(data)
                        }catch (e) {
                            // 频道已关闭,重新创建频道
                            this.delete(channelname)
                            this.open(channelname)
                            this.postMessage(channelname, data)
                        }
                    }else{
                        console.warn('【channel:'+channelname+'】: channel is not defined, you should first execute open method');
                    }
                }
                // 初始化
                this.reset = function (){
                    // 频道名称集合
                    this.channelMap = new Map()
                    this.channelLength = this.getLength()
                }
                this.reset()
            }

            const channel = new BroadChannel((data)=>{
                console.log(data);

            })
            channel.open('test').postMessage('test',111)
            channel.open('test2').postMessage('test2',222)
            console.log(channel);


    4. ShareWorker

    SharedWorker是HTML5提供的一种Web Worker类型,它允许多个浏览器上下文(如多个窗口、标签页或框架)共享相同的Worker实例。与普通的Worker不同,SharedWorker可以跨浏览器上下文进行通信和共享数据
    worker1
    worker2

    5.本地缓存 LocalStorage和SessionStorage
    LocalStorage和SessionStorage是浏览器提供的本地存储方案。它们可以在浏览器端存储和读取数据,并在同一域名下的不同页面间进行数据共享。LocalStorage和SessionStorage适用于在同一浏览器中的不同页面之间进行数据传递的需求

    6. MessageChannel
    Channel Messaging API 的 MessageChannel 接口允许我们创建一个新的消息通道,并通过它的两个 MessagePort 属性发送数据
    消息频道

    事件总线
    事件总线是一种在应用程序中实现组件间通信的机制。它允许组件之间通过订阅和发布事件来进行信息传递,无论这些组件是父子组件、兄弟组件或跨越组件树的。
    事件总线的实现可以是一个全局的事件管理器或服务,也可以是一个专门为事件通信而创建的组件

    方式1:
    import mitt from 'mitt'
    const EventBus = mitt();


    方式2
    const EventBus = new Vue()

    事件总线方法:

    EventBus.on("on-preview")
    EventBus.emit("on-preview", '图片地址')
    EventBus.off("on-preview")



    7.交互通信
    WebViewJavascriptBridge是一个用于在WebView与JavaScript之间进行双向通信的桥接库。它允许原生应用程序的WebView与嵌入的JavaScript通过桥接对象进行交互,实现数据传输和方法调用

    js代码:

    /*这段代码是固定的,必须要放到js中*/
    function setupWebViewJavascriptBridge(callback) {
      //判断机型
      let u = navigator.userAgent;

      if (window.WebViewJavascriptBridge) {
        return callback(WebViewJavascriptBridge);
      }

      //判断是否是ios
      if (/(iPhone|iPad|iPod|iOS|Mac OS)/i.test(u)) {
        if (window.WVJBCallbacks) {
          return window.WVJBCallbacks.push(callback);
        }
        window.WVJBCallbacks = [callback];
        let WVJBIframe = document.createElement('iframe');
        WVJBIframe.style.display = 'none';
        WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
        document.documentElement.appendChild(WVJBIframe);
        setTimeout(function() {
          document.documentElement.removeChild(WVJBIframe);
        }, 0);
      } else {
        document.addEventListener(
          'WebViewJavascriptBridgeReady',
          function() {
            callback(WebViewJavascriptBridge)
          },
          false
        );
      }
    }
    let Bridge = {};
    Bridge.install = function (Vue, options) {
      Vue.prototype.$bridge = {};
      /*与OC交互的所有JS方法都要放在此处注册,才能调用通过JS调用OC或者让OC调用这里的JS*/
      setupWebViewJavascriptBridge(function(bridge) {
        // 普通环境 - 生命全局变量
        //初始化
        //判断机型
        let u = navigator.userAgent;
        if (!/(iPhone|iPad|iPod|iOS|Mac OS)/i.test(u)) {
          bridge.init(function(message, responseCallback) {
            let data = {
              'Javascript Responds': 'Wee!'
            };
            alert("jasdashjd");
            responseCallback(data);
          });
        }
        Vue.prototype.$bridge = bridge;
      });
      //
      // setupWebViewJavascriptBridge(function (bridge) {
      //   Vue.prototype.$bridge = bridge;
      // })

    }
    export default Bridge;


    8.安卓端代码:

    // 创建WebViewJavascriptBridge实例
    WebViewJavascriptBridge bridge = new WebViewJavascriptBridge(context, webView, new BridgeHandler() {
        @Override
        public void handler(String data, CallBackFunction responseCallback) {
            // 处理JavaScript发送的消息
            // ...

            // 发送响应给JavaScript
            responseCallback.onCallBack("Android response");
        }
    });

    // 注册一个Native Handler用于处理JavaScript请求
    bridge.registerHandler("jsHandler", new BridgeHandler() {
        @Override
        public void handler(String data, CallBackFunction responseCallback) {
            // 处理JavaScript请求
            // ...

            // 发送响应给JavaScript
            responseCallback.onCallBack("Android response");
        }
    });

    // 发送消息给JavaScript
    bridge.callHandler("nativeHandler", "Android message", new CallBackFunction() {
        @Override
        public void onCallBack(String responseData) {
            // 处理JavaScript响应
            // ...
        }
    });


    9.ios端代码:

    // 导入WebViewJavascriptBridge头文件
    #import "WebViewJavascriptBridge.h"

    // 创建一个WebViewJavascriptBridge实例
    WebViewJavascriptBridge *bridge = [WebViewJavascriptBridge bridgeForWebView:webView];

    // 注册一个处理Native请求的handler
    [bridge registerHandler:@"nativeHandler" handler:^(id data, WVJBResponseCallback responseCallback) {
        // 处理Native请求,如获取设备信息等
        // ...

        // 回调JavaScript
        responseCallback(@"Native response");
    }];

    // 发送消息给JavaScript
    [bridge callHandler:@"jsHandler" data:@"Native message" responseCallback:^(id responseData) {
        // 处理JavaScript响应
        // ...
    }];


    10.其他通信:
AJAX是一种通过在后台与服务器进行数据交换的技术。通过在页面上使用JavaScript,可以异步地发送HTTP请求,获取数据并更新页面内容,实现与服务器的数据交互
WebSocket是一种在单个TCP连接上进行全双工通信的协议。它允许在客户端和服务器之间实时传输数据,同时支持服务器向客户端主动推送数据。WebSocket能够提供实时性和双向通信的能力,非常适合实时应用程序、即时通讯以及在线游戏等场景
Server
-Sent Events是一种基于HTTP的服务器向客户端推送事件的技术。与WebSocket不同,SSE是一种单向通信机制,服务器可以向客户端推送数据,但客户端不能主动向服务器发送请求。SSE适用于需要实时更新的应用场景,如实时新闻、股票行情等
WebRTC(Web Real
-Time Communication)是一种支持浏览器之间进行实时通信的开放性标准。它提供了音视频通信、数据传输和P2P文件共享等功能。WebRTC可以在Web应用程序中实现实时语音、视频通话和文件传输,同时也可以用于游戏、即时通讯和远程协作等场景 以及其他通信方式
注意 js开发中,通信问题一般都与浏览器安全协议有着密切的关系,也就是我们常说的跨域问题,面对不同的场景,可以选择不同的通信方式 使用Web API实现相关通信的方案时,需要考虑浏览器兼容性,一般主流浏览器都兼容,像IE或低版本浏览器会有兼容性问题
   具体可以在MDN或者Can I Use网站查看

 

posted @ 2024-02-20 11:13  libenzheng  阅读(225)  评论(0)    收藏  举报