欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Web Worker線程解決方案electron踩坑記錄

 更新時間:2022年11月08日 10:26:33   作者:會聯(lián)營的陸遜  
這篇文章主要為大家介紹了Web Worker線程解決方案electron踩坑記錄,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

初始化項目

electron 開發(fā)時會遇到一對多的情況,在進(jìn)行 websocket 通信時,如果接收到服務(wù)端多個指令時,而這個指令剛好需要占用線程,這個時候整個界面就會失去響應(yīng),那么我們就可以使用線程來解決這個問題.

npm create vite@latest electron-worker

執(zhí)行完后修改 package.json 如下:

{
  "name": "electron-worker",
  "private": true,
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {},
  "devDependencies": {
    "@vitejs/plugin-vue": "^3.2.0",
    "vite": "^3.2.0",
    "vue": "^3.2.41",
    "electron": "19.1.4",
    "electron-builder": "^23.3.3"
  }
}

編寫入口文件和 electron 插件

創(chuàng)建 mainEntry.js 作為 electron 的入口文件,啟動一個窗口

// src/main/mainEntry.js
import { app, BrowserWindow } from "electron";
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = "true";
let mainWindow;
app.whenReady().then(() => {
  let config = {
    webPreferences: {
      nodeIntegration: true,
      webSecurity: false,
      allowRunningInsecureContent: true,
      contextIsolation: false,
      webviewTag: true,
      spellcheck: false,
      disableHtmlFullscreenWindowResize: true,
    },
  };
  mainWindow = new BrowserWindow(config);
  mainWindow.webContents.openDevTools({ mode: "undocked" });
  mainWindow.loadURL(process.argv[2]);
});

編寫 vite 插件,在服務(wù)器啟動后加載 electron 入口文件

// plugins/devPlugin.js
export const devPlugin = () => {
  return {
    name: "dev-plugin",
    configureServer(server) {
      require("esbuild").buildSync({
        entryPoints: ["./src/main/mainEntry.js"],
        bundle: true,
        platform: "node",
        outfile: "./dist/mainEntry.js",
        external: ["electron"],
      });
      server.httpServer.once("listening", () => {
        let { spawn } = require("child_process");
        let electronProcess = spawn(require("electron").toString(), ["./dist/mainEntry.js", `http://127.0.0.1:${server.config.server.port}/`], {
          cwd: process.cwd(),
          stdio: "inherit",
        });
        electronProcess.on("close", () => {
          server.close();
          process.exit();
        });
      });
    },
  };
};

使用插件

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { devPlugin } from "./plugins/devPlugin";
export default defineConfig({
  plugins: [devPlugin(), vue()],
})

將 vue 項目文件放入和 main 同級, 結(jié)構(gòu)如下所示

└─src 
    ├─main
    │      mainEntry.js  
    └─renderer
        │  App.vue
        │  main.js
        ├─assets
        └─components

修改 index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" rel="external nofollow"  />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + Vue</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/renderer/main.js"></script>
  </body>
</html>

現(xiàn)在執(zhí)行 npm run dev 就可以運行項目了

websocket

websocket 服務(wù)

var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({port: 8181});
wss.on('connection', function (ws) {
  console.log('有客戶端連接');
  ws.send("連接成功")
  ws.on('message', function (jsonStr) {
    console.log(jsonStr.toString());
  });
});

連接 websocket 服務(wù)

準(zhǔn)備 Socket 對象

export default class Socket {
  websocket
  wsUrl
  constructor(wsUrl) {
    this.wsUrl = wsUrl
  }
  init() {
    if (this.websocket) return this.websocket
    const socket = this.websocket = new WebSocket(this.wsUrl)
    // WebSocket 接收服務(wù)端數(shù)據(jù)
    socket.onmessage = (e) => {
      console.log("接收服務(wù)端消息:", e.data)
    }
    // WebSocket 斷開連接后觸發(fā)
    socket.onclose = (e) => {}
    // WebSocket 連接成功
    socket.onopen = () => {
      console.log("連接成功")
    }
    // WebSocket 連接異常
    socket.onerror = (e) => {}
  }
}

連接 Socket

<script setup>
import Socket from './socket'
const socket = new Socket("ws://localhost:8181")
function register() {
  socket.init()
}
</script>
<template>
  <div>
    <button @click="register">注冊</button>
  </div>
</template>
<style scoped>
</style>

點擊注冊后顯示如下:

發(fā)送心跳

一般為了確保服務(wù)一直連接,需要客戶端定時給服務(wù)發(fā)送心跳

export default class Socket {
  // ...
  heartbeatCount // 心跳次數(shù)
  heartbeatTimer // 心跳定時器
  heartbeatInterval = 1000 * 20 // 心跳發(fā)送頻率(2秒一次)
  // ...
  sendHeartBeat() {
    this.heartbeatCount = 0
    if (this.heartbeatTimer) clearInterval(this.heartbeatTimer)
    this.heartbeatTimer = setInterval(() => {
      this.websocket.send("發(fā)送心跳")
    }, this.heartbeatInterval)
  }
}

App.vue

function sendHeartBeat() {
  socket.sendHeartBeat()
}
<button @click="sendHeartBeat">發(fā)送心跳</button>

可以看到我們在服務(wù)端日志里看到有持續(xù)心跳日志

取消心跳

因為是定時器發(fā)送,當(dāng)服務(wù)端掉線后定時器卻還在繼續(xù)發(fā)送,現(xiàn)在我們來優(yōu)化這個

// 斷開連接
onclose() {
  console.log("已斷開連接")
  this.websocket = null
  // 清除心跳定時器
  if (this.heartbeatTimer) clearInterval(this.heartbeatTimer)
}

在 socket 斷開后進(jìn)行調(diào)用

// WebSocket 斷開連接后觸發(fā)
socket.onclose = (e) => {
  this.onclose()
}

重新連接

websocket 斷開有可能是客戶端網(wǎng)絡(luò)問題,所以我們需要進(jìn)行嘗試重連

export default class Socket {
  // ...
  socketOpen // 是否連接
  isReconnect = true // 是否可以重新連接
  reconnectCountMax = 3 // 最大重新次數(shù)
  reconnectTimer // 重連定時器
  reconnectCurrent = 0  // 重連次數(shù)
  reconnectInterval // 1000 * 3 // 重連頻率(3秒一次)
  // ...
  // 斷開連接
  onclose() {
    console.log("已斷開連接")
    this.websocket = null
    // 清除心跳定時器
    if (this.heartbeatTimer) clearInterval(this.heartbeatTimer)
    // 需要重新連接
    if (this.isReconnect) {
      this.reconnectTimer = setTimeout(() => {
        if (this.reconnectCurrent >= this.reconnectCountMax) {
          console.log("超過重連次數(shù),重連失敗")
          clearTimeout(this.reconnectTimer)
        } else {
          this.reconnectCurrent += 1
          this.reconnect()
        }
      }, this.reconnectInterval)
    }
  }
  // 重新連接
  reconnect() {
    console.log("重新連接", this.reconnectCurrent)
    if (this.websocket && this.socketOpen) {
      this.websocket.close()
    }
    this.init()
  }
}

我們每三秒一次進(jìn)行嘗試重新連接,如果重連三次還未連接,那我們認(rèn)為無法重新連接

其它優(yōu)化

export enum PostMessageType {
  ON_OPEN = 'open', // websocket開啟
  ON_ERROR = 'error', // websocket異常
  ON_CLOSE = 'close', // websocket關(guān)閉
  ON_MESSAGE = 'message', // websocket接收消息
  RECONNECT = 'reconnect', // websocket重新連接
  HEARTBEAT = 'heartbeat', // websocket發(fā)送心跳
  OFF = 'off', // websocket主動關(guān)閉
  REGISTER = 'register', // websocket注冊成功
}
class Socket {
  wsUrl: string // 服務(wù)地址
  websocket: WebSocket | null = null // websocket對象
  socketOpen: boolean = false // socket是否開啟
  heartbeatTimer: any // 心跳定時器
  heartbeatCount: number = 0 // 心跳次數(shù)
  heartbeatInterval: number = 1000 * 20 // 心跳發(fā)送頻率(2秒一次)
  isReconnect: boolean = true // 是否可以重新連接
  reconnectCountMax: number = 3 // 最大重新次數(shù)
  reconnectCurrent: number = 0 // 已發(fā)起重連次數(shù)
  reconnectTimer: any // 重連timer
  reconnectInterval: number = 1000 * 3 // 重連頻率(3秒一次)
  constructor(url: string) {
    this.wsUrl = url
  }
  // socket 初始化
  init() {
    if (this.websocket) return this.websocket
    const socket = this.websocket = new WebSocket(this.wsUrl)
    // WebSocket 接收服務(wù)端數(shù)據(jù)
    socket.onmessage = (e) => {
      this.receive(e.data)
    }
    // WebSocket 斷開連接后觸發(fā)
    socket.onclose = (e) => {
      this.postMessage(PostMessageType.ON_CLOSE, e)
      this.onclose()
    }
    // WebSocket 連接成功
    socket.onopen = () => {
      this.onopen()
    }
    // WebSocket 連接異常
    socket.onerror = (e) => {
      this.postMessage(PostMessageType.ON_ERROR, e)
    }
  }
  // 連接成功后的回調(diào)
  onopen() {
    this.socketOpen = true
    this.isReconnect = true
    this.reconnectCurrent = 1
    this.heartbeatCount = 0
    this.postMessage(PostMessageType.ON_OPEN)
  }
  /**
   * 消息處理器
   * @param type
   * @param data
   */
  postMessage(type: PostMessageType, data?: any) {}
  /**
   * 斷開連接
   */
  onclose() {
    this.websocket = null
    this.socketOpen = false
    // 清除心跳定時器
    clearInterval(this.heartbeatTimer)
    // 需要重新連接
    if (this.isReconnect) {
      this.reconnectTimer = setTimeout(() => {
        if (this.reconnectCurrent >= this.reconnectCountMax) {
          clearTimeout(this.reconnectTimer)
        } else {
          this.reconnectCurrent += 1
          this.reconnect()
        }
      }, this.reconnectInterval)
    }
  }
  /**
   * 重新連接
   */
  reconnect() {
    this.postMessage(PostMessageType.RECONNECT, this.reconnectCurrent)
    if (this.websocket && this.socketOpen) {
      this.websocket.close()
    }
    this.init()
  }
  /**
   * 給服務(wù)端發(fā)送消息
   * @param data
   * @param callback
   */
  send(data: any, callback?: () => void) {
    const ws = this.websocket
    if (!ws) {
      this.init()
      setTimeout(() => {
        this.send(data, callback)
      }, 1000)
      return
    }
    switch (ws.readyState) {
      case ws.OPEN:
        ws.send(data)
        if (callback) {
          callback()
        }
        break
      case ws.CONNECTING:
        // 未開啟,則等待1s后重新調(diào)用
        setTimeout(() => {
          this.send(data, callback)
        }, 1000)
        break
      default:
        this.init()
        setTimeout(() => {
          this.send(data, callback)
        }, 1000)
    }
  }
  receive(data: any) {
    this.postMessage(PostMessageType.ON_MESSAGE, data)
  }
  /**
   * 發(fā)送心跳
   * @param data 心跳數(shù)據(jù)
   */
  sendHeartBeat(data: any) {
    this.heartbeatCount = 0
    if (this.heartbeatTimer) clearInterval(this.heartbeatTimer)
    this.heartbeatTimer = setInterval(() => {
      this.send(data, () => {
        this.heartbeatCount += 1
        this.postMessage(PostMessageType.HEARTBEAT, { heartBeatData: data, heartbeatCount: this.heartbeatCount })
      })
    }, this.heartbeatInterval)
  }
  /**
   * 主動關(guān)閉websocket連接
   * 關(guān)閉后 websocket 關(guān)閉監(jiān)聽可以監(jiān)聽到,所以無需去額外處理
   */
  close() {
    this.isReconnect = false
    this.postMessage(PostMessageType.OFF, "主動斷開websocket連接")
    this.websocket && this.websocket.close()
  }
}

上面是基礎(chǔ)的 websocket ,具體使用需要結(jié)合業(yè)務(wù)進(jìn)行繼承使用

export default class SelfSocket extends Socket {
  registerData: any // 注冊數(shù)據(jù)
  heartBeatData: any // 心跳數(shù)據(jù)
  constructor(url: string) {
    super(url);
  }
  initSocket(registerData: any, heartBeatData: any) {
    this.registerData = registerData
    this.heartBeatData = heartBeatData
    super.init()
  }
  onopen() {
    this.register()
    super.onopen();
  }
  /**
   * websocket 注冊消息,注冊成功后進(jìn)行心跳發(fā)送
   */
  register() {
    this.send(this.registerData, () => {
      this.sendHeartBeat(this.heartBeatData)
      this.postMessage(PostMessageType.REGISTER, this.registerData)
    })
  }
  send(data: any, callback?: () => void) {
    // 數(shù)據(jù)加密
    const str = _encrypt(data)
    super.send(str, callback);
  }
  receive(data: any) {
    this.postMessage(PostMessageType.ON_MESSAGE, _decode(data))
  }
  postMessage(type: PostMessageType, e?: any) {}
}

我們公司 websocket 連接需要注冊后進(jìn)行心跳發(fā)送,且在接收和發(fā)送數(shù)據(jù)時都進(jìn)行了加密和解密,簡單的可以使用 base64 進(jìn)行

Worker

Web Worker 使用可以參考阮一峰老師的文章,這里就不做過多介紹

創(chuàng)建一個 websocketWorker.js

const URL = "ws://localhost:8181"
import Socket from "./socket";
const ws = new Socket(URL)
self.addEventListener('message', (e) => {
  const { type, data } = e.data
  switch (type) {
    case "init":
      ws.init();
      break
    case "message":
      ws.send(data)
      break
    case "close":
      ws.close()
      break
    default:
      console.error("發(fā)送websocket命令有誤")
      break
  }
})
<script setup>
import Worker from './websocketWorker?worker'
const worker = new Worker()
worker.onmessage = function (e) {
  console.log(e.data)
}
function register() {
  worker.postMessage({
    type: 'init'
  })
}
function close() {
  worker.postMessage({
    type: 'close'
  })
}
</script>
<template>
  <div>
    <button @click="register">注冊</button>
    <button @click="close">關(guān)閉服務(wù)</button>
  </div>
</template>

vite 使用 worker 可以查看 worker選項

如果是 webpack 可以查看 worker-loader

module.exports = {
  chainWebpack: config => {
    config.module
      .rule('worker')
      .test(/.worker.js$/)
      .use('worker-loader')
      .loader('worker-loader')
      .options({
        inline: 'no-fallback',
      })
      .end()
    config.module.rule('js').exclude.add(/.worker.js$/)
  }
}

這里是我的配置

以上就是Web Worker線程解決方案electron踩坑記錄的詳細(xì)內(nèi)容,更多關(guān)于Web Worker線程electron的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 一文了解什么是TypeScript?

    一文了解什么是TypeScript?

    這篇文章主要介紹了什么是TypeScript,TypeScript是JavaScript的超集,它可以編譯成純JavaScript代碼,TypeScript可以運行在瀏覽器環(huán)境、Node.js環(huán)境或者ECMAScript3或者更高的JavaScript的引擎中,下面我們就進(jìn)入文章一起學(xué)習(xí)TypeScript的詳細(xì)內(nèi)容吧
    2021-12-12
  • 快速保存網(wǎng)頁中所有圖片的方法

    快速保存網(wǎng)頁中所有圖片的方法

    快速保存網(wǎng)頁中所有圖片的方法...
    2006-06-06
  • 微信小程序 教程之模板

    微信小程序 教程之模板

    這篇文章主要介紹了微信小程序 模板的相關(guān)資料,并附實例代碼,需要的朋友可以參考下
    2016-10-10
  • 微信小程序 中wx.chooseAddress(OBJECT)實例詳解

    微信小程序 中wx.chooseAddress(OBJECT)實例詳解

    這篇文章主要介紹了微信小程序 中wx.chooseAddress(OBJECT)實例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • JS實現(xiàn)將圖片URL轉(zhuǎn)base64示例詳解

    JS實現(xiàn)將圖片URL轉(zhuǎn)base64示例詳解

    這篇文章主要為大家介紹了JS實現(xiàn)將圖片URL轉(zhuǎn)base64示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 微信小程序 Buffer緩沖區(qū)的詳解

    微信小程序 Buffer緩沖區(qū)的詳解

    這篇文章主要介紹了 微信小程序 Buffer緩沖區(qū)的詳解的相關(guān)資料,需要的朋友可以參考下
    2017-07-07
  • 微信小程序 合法域名校驗出錯詳解及解決辦法

    微信小程序 合法域名校驗出錯詳解及解決辦法

    這篇文章主要介紹了微信小程序 合法域名校驗出錯詳解及解決辦法的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • Intl對象DateTimeFormat?ListFormat?RelativeTimeFormat使用講解

    Intl對象DateTimeFormat?ListFormat?RelativeTimeFormat使用講解

    這篇文章主要為大家介紹了Intl對象DateTimeFormat?ListFormat?RelativeTimeFormat使用講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • ResizeObserver 監(jiān)視 DOM大小變化示例詳解

    ResizeObserver 監(jiān)視 DOM大小變化示例詳解

    這篇文章主要為大家介紹了ResizeObserver 監(jiān)視 DOM大小變化示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • js 數(shù)組 fill() 填充方法

    js 數(shù)組 fill() 填充方法

    這篇文章主要介紹了js 數(shù)組 fill() 的填充方法,初始化數(shù)組的方法,但是初始化數(shù)組之后,數(shù)組中的每一項元素默認(rèn)為 empty 空位占位,如何對數(shù)組這些空位添加默認(rèn)的元素,ES6提供了 fill() 方法實現(xiàn)這一操作。本文總結(jié)數(shù)組 fill() 方法的詳細(xì)使用,需要的朋友可以參考一下
    2021-10-10

最新評論