前端微服务 websocket的简易封装,以及iframe如

一、功能解读

  • 主应用封装 ws, 子应用共享;
  • 心跳检测、自动重连;
  • iframe子应用 订阅、推送(onPubSocket 、onSubSocket);

二、代码片段

类型自行忽略


import _ from 'lodash'
import store from '../store'
// import { Notice } from 'view-design'
import Notification from '../components/Notification'
import { Callback, eventsMessageItem, wsOptions, resultType } from '../model/websocket'

class Websocket {

  private websocket: any // ws 实体
  private timer: any // 心跳检测定时器
  private socketUrl: string // ws url
  private timeout: number // 心跳检测时间间隔
  private serverPort: number // ws 端口号
  private isConnect: boolean = false // ws 是否连接
  private eventsQueue: Record<string, Callback[]> = {} // pud sub 消息订阅推送队列
  public eventsMessage: eventsMessageItem[] = [] // 保存的消息 只保存最新的20条

  constructor (wsOpt: wsOptions) {
    const { socketUrl, serverPort, timeout } = wsOpt
    this.socketUrl = socketUrl
    if (serverPort) this.serverPort = serverPort
    if (timeout) this.timeout = timeout
  }

  private createWebSocket = () => {
    if( typeof WebSocket === 'undefined' ) return console.error("您的浏览器不支持Websocket通信协议!")
    if (this.websocket) return
    this.initWebSocket()
  }
  // 初始化websocket
  public initWebSocket = () => {
    // noticeOpen()
    this.websocket = new WebSocket(this.socketUrl)
    // 连接成功
    this.websocket.onopen = (e) => {
      this.isConnect = true
      this.openStatus(e)
    }
    // 连接关闭
     this.websocket.onclose = (e) => {
      this.closeStatus(e)
    }
    // 接收信息
    this.websocket.onmessage = (e) => {
      this.onmessage(e)
    }
    // 连接发生错误的回调方法
    this.websocket.onerror = (e) => {
      console.log(`ws 连接错误:${e}`)
    }
  }

  // 重连
  private reconnect = () => {
    let cTimer: any = null
    cTimer && clearTimeout(cTimer)
    cTimer = setTimeout(() => {
      this.initWebSocket()
    }, 5000)
  }

  // 心跳检测
  private socketHeartbeat = () => {
    if (!this.isConnect) return
    this.timer && clearTimeout(this.timer)
    this.timer = setTimeout(() => {
      if (this.websocket.readyState === 1) {  // 连接正常 发送心跳包
        console.log(`ws: 开启心跳检测 --- 发送心跳包`)
        this.websocket.send(JSON.stringify({
          type: 'heartbeat',
          msg: 'heartbeat message'
        }));
      } else {  // 否则重连
        this.isConnect = false
        this.reconnect();
      }
    }, this.timeout)
  }

  // 重置心跳
  private onReset = () => {
    console.log(`ws: 重置心跳`)
    clearTimeout(this.timer)
    // 重启心跳
    this.socketHeartbeat()
  }

  // 数据接收
  private onmessage = (e) => {
    _.debounce(() => this.socketHeartbeat(), 2000)()
    this.handleMessage(e)
  }

  // 消息处理
  private handleMessage = (e) => {
    const res = JSON.parse(e.data)
    const { type, data } = res

    switch (type) {
      case 'heartbeat': // 心跳
        console.info(`ws: 心跳正常`)
        break;
      case 'resource': // 资源数据
        setDashboard(data)
        break;
      case 'new-message': // 消息通知
        store.commit(`Launcher/updateNemMsg`, data)
        break;
      case 'task-total': // 任务
        store.commit(`Launcher/updateIsTask`, data)
        break;
      case 'app-update-total': // 应用数据
        this.onSubSocket('app-update-total', 'ws: message')
        break;
      default: // 其他通知
        const length = this.eventsMessage.length
        if (length >= 20) {
          this.eventsMessage.shift()
          this.eventsMessage.push(res)
        }
        // this.onSubSocket('notify', 'ws: message')
    }
  }

  // 发布
  public onPubSocket = (eventName: string, cb: Callback) => {
    const query: Callback[] = this.eventsQueue[eventName] || [] // 获取原队列
    query.push(cb)  // 队列中追加cb
    this.eventsQueue[eventName] = query // 重新赋值事件队列
  }

  // 订阅
  public onSubSocket = (eventName: string, ...args: any[]) => {
    const query: Callback[] = this.eventsQueue[eventName] || [] //  获取事件队列
    if (query.length < 1) return 
    query.forEach((t: Callback) => { t(...args) }) // 执行事件队列中的回调函数数组
  }

  // 打开状态
  private openStatus = (e) => {
    console.log(`ws 连接成功:${e}`)
  }

  // 数据发送
  public websocketSend = (data) => {
    this.websocket.send(data)
  }

  // 关闭状态
  private closeStatus = (e) => {
    console.log(`ws 连接关闭:${e}`)
  }

  // 关闭
  public onClose = () => {
    this.isConnect = false
    clearTimeout(this.timer)
    this.timer = null
    this.websocket.close()
  }
}

const setDashboard = (data: resultType) => {
  switch (data.name) {
    case 'memory': // 内存 使用率
      store.commit(`Launcher/updateDegRam`, data.usage * 1.8)
      break;
    case 'cpu': // cpu 使用率
      store.commit(`Launcher/updateDegCpu`, data.usage * 1.8)
      break;
    case 'network': // 上传下载速率
      store.commit(`Launcher/updateReceive`, data.receive)
      store.commit(`Launcher/updateTransmit`, data.transmit)
      break;
    default:
      break;
  }
}
 
export default new Websocket({
  socketUrl: 'ws://192.168.24.26:9999/ugreen/v1/desktop/ws',
  serverPort: 80,
  timeout: 25000
})


三、示例

3.1 主应用初始化

// ws 相关
initWebSocket () {
    Websocket.initWebSocket()
    Websocket.onPubSocket('state', (data) => {
      console.log(`这是监听到 ws 的消息:${data}`)
    })
    this.$once('hook:beforeDestroy', function () {
      Websocket.onClose()
      window.removeEventListener("message", () => {})
    })
},

3.2 子应用监听看下方使用文档

四、使用文档


#### websocket 使用说明

##### 1. 介绍

- 1.1 ws 的心跳检测时间是 25s, 可自定义

- 1.2 ws 意外断开重连时间是心跳检测时间的基础上 + 5s

- 1.3 launcher 桌面端会实时接收 server 端推送的消息, 并全部记录在 eventsMessage 内

- 1.4 接收消息后会主动调用 onSubSocket 方法通知订阅者

- 1.5 接收者通过 注册 onPubSocket 方法接收

##### 2. 使用

挂在到window: window.customWebsocket = websocket

- 2.1 通知订阅者示例

```js
 Websocket.onSubSocket(msgType, 'ws: message')
```

*   2.1 接收者示例

```js
 Websocket.onPubSocket(msgType, (msg) => {})
```

##### 3. 其他模块使用

*   3.1 当挂在在全局 window 上 属性为 customWebsocket; msgType需一致

```js
// launcher 应用
 Websocket.onSubSocket(msgType, 'ws: message')

// 子应用接收示例
(window.top as any).customWebsocket.onPubSocket(msgType, (msg) => {})

```

*   3.1 当 通过 postMessage 方式接收时

```js
// launcher 应用 msgObj 会包含type 消息类型, 子应用自行过滤
 window.top.postMessage(msgObj, '*')

// 子应用接收示例
(top as any).addEventListener('message', (msgObj) => {})

```
全部评论

相关推荐

最近又搬回宿舍了,在工位坐不住,写一写秋招起伏不断的心态变化,也算对自己心态的一些思考表演式学习从开始为实习准备的时候就特别焦虑,楼主一开始选择的是cpp后端,但是24届这个方向已经炸了,同时自己又因为本科非92且非科班,所以感到机会更加迷茫。在某天晚上用java写出hello&nbsp;world并失眠一整晚后选择老本行干嵌入式。理想是美好的,现实情况是每天忙但又没有实质性进展,总是在配环境,调工具,顺带还要推科研。而这时候才发现自己一直在表演式学习,徘徊在设想如何展开工作的循环里,导致没有实质性进展。现在看来当时如果把精力专注在动手写而不是两只手端着看教程,基本功或许不会那么差。实习的焦虑5月,楼主...
耶比:哲学上有一个问题,玛丽的房间:玛丽知道眼睛识别色彩的原理知道各种颜色,但是她生活在黑白的房间里,直到有一天玛丽的房门打开了她亲眼看到了颜色,才知道什么是色彩。我现在最大可能的减少对非工作事情的思考,如果有一件事困扰了我, 能解决的我就直接做(去哪里或者和谁吵架等等……),解决不了的我就不想了,每一天都是最年轻的一天,珍惜今天吧
投递比亚迪等公司10个岗位 > 秋招被确诊为…… 牛客创作赏金赛
点赞 评论 收藏
分享
美团 后端开发 总包n(15%是股票)
点赞 评论 收藏
分享
双非坐过牢:非佬,可以啊10.28笔试,11.06评估11.11,11.12两面,11.19oc➕offer
点赞 评论 收藏
分享
斑驳不同:还为啥暴躁 假的不骂你骂谁啊
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务