91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Web?Worker線程electron問題怎么解決

發布時間:2022-11-09 09:24:40 來源:億速云 閱讀:243 作者:iii 欄目:開發技術

本文小編為大家詳細介紹“Web Worker線程electron問題怎么解決”,內容詳細,步驟清晰,細節處理妥當,希望這篇“Web Worker線程electron問題怎么解決”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。

    初始化項目

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

    npm create vite@latest electron-worker

    執行完后修改 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 插件

    創建 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 插件,在服務器啟動后加載 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 同級, 結構如下所示

    └─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>

    現在執行 npm run dev 就可以運行項目了

    websocket

    websocket 服務

    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 服務

    準備 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 接收服務端數據
        socket.onmessage = (e) => {
          console.log("接收服務端消息:", e.data)
        }
        // WebSocket 斷開連接后觸發
        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>

    點擊注冊后顯示如下:

    Web?Worker線程electron問題怎么解決

    發送心跳

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

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

    App.vue

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

    Web?Worker線程electron問題怎么解決

    可以看到我們在服務端日志里看到有持續心跳日志

    取消心跳

    因為是定時器發送,當服務端掉線后定時器卻還在繼續發送,現在我們來優化這個

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

    在 socket 斷開后進行調用

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

    重新連接

    websocket 斷開有可能是客戶端網絡問題,所以我們需要進行嘗試重連

    export default class Socket {
      // ...
      socketOpen // 是否連接
      isReconnect = true // 是否可以重新連接
      reconnectCountMax = 3 // 最大重新次數
      reconnectTimer // 重連定時器
      reconnectCurrent = 0  // 重連次數
      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("超過重連次數,重連失敗")
              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()
      }
    }

    我們每三秒一次進行嘗試重新連接,如果重連三次還未連接,那我們認為無法重新連接

    其它優化

    export enum PostMessageType {
      ON_OPEN = 'open', // websocket開啟
      ON_ERROR = 'error', // websocket異常
      ON_CLOSE = 'close', // websocket關閉
      ON_MESSAGE = 'message', // websocket接收消息
      RECONNECT = 'reconnect', // websocket重新連接
      HEARTBEAT = 'heartbeat', // websocket發送心跳
      OFF = 'off', // websocket主動關閉
      REGISTER = 'register', // websocket注冊成功
    }
    class Socket {
      wsUrl: string // 服務地址
      websocket: WebSocket | null = null // websocket對象
      socketOpen: boolean = false // socket是否開啟
      heartbeatTimer: any // 心跳定時器
      heartbeatCount: number = 0 // 心跳次數
      heartbeatInterval: number = 1000 * 20 // 心跳發送頻率(2秒一次)
      isReconnect: boolean = true // 是否可以重新連接
      reconnectCountMax: number = 3 // 最大重新次數
      reconnectCurrent: number = 0 // 已發起重連次數
      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 接收服務端數據
        socket.onmessage = (e) => {
          this.receive(e.data)
        }
        // WebSocket 斷開連接后觸發
        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)
        }
      }
      // 連接成功后的回調
      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()
      }
      /**
       * 給服務端發送消息
       * @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后重新調用
            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)
      }
      /**
       * 發送心跳
       * @param data 心跳數據
       */
      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)
      }
      /**
       * 主動關閉websocket連接
       * 關閉后 websocket 關閉監聽可以監聽到,所以無需去額外處理
       */
      close() {
        this.isReconnect = false
        this.postMessage(PostMessageType.OFF, "主動斷開websocket連接")
        this.websocket && this.websocket.close()
      }
    }

    上面是基礎的 websocket ,具體使用需要結合業務進行繼承使用

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

    Worker

    創建一個 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("發送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">關閉服務</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問題怎么解決”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    抚松县| 赤峰市| 宁津县| 新津县| 凭祥市| 辛集市| 庆城县| 彭山县| 庄浪县| 广元市| 望江县| 青阳县| 大厂| 松潘县| 洪湖市| 怀远县| 大化| 梅州市| 华坪县| 平潭县| 巧家县| 故城县| 柳州市| 民和| 门头沟区| 铜陵市| 临邑县| 定陶县| 汝阳县| 资兴市| 驻马店市| 祥云县| 望城县| 合作市| 体育| 饶阳县| 达日县| 长武县| 伊吾县| 巫溪县| 漠河县|