我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Web Worker线程electron问题怎么解决

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Web Worker线程electron问题怎么解决

本文小编为大家详细介绍“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 的入口文件,启动一个窗口

    // class="lazy" data-src/main/mainEntry.jsimport { 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.jsexport const devPlugin = () => {  return {    name: "dev-plugin",    configureServer(server) {      require("esbuild").buildSync({        entryPoints: ["./class="lazy" data-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 同级, 结构如下所示

    └─class="lazy" data-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" class="lazy" data-src="/class="lazy" data-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)  }    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()  }    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)  }    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)  }    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();  }    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问题怎么解决”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网行业资讯频道。

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    Web Worker线程electron问题怎么解决

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档

    猜你喜欢

    Web Worker线程electron问题怎么解决

    本文小编为大家详细介绍“Web Worker线程electron问题怎么解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“Web Worker线程electron问题怎么解决”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习
    2023-07-04

    qt线程抢占问题怎么解决

    Qt线程抢占问题指的是多个线程同时访问共享资源时可能导致的数据竞争和不确定性的问题。下面是一些解决Qt线程抢占问题的方法:使用互斥锁(QMutex)或读写锁(QReadWriteLock)来保护共享资源。在访问共享资源之前,先获取互斥锁或读
    qt线程抢占问题怎么解决
    2024-02-29

    Java多线程之线程安全问题怎么解决

    本篇内容主要讲解“Java多线程之线程安全问题怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java多线程之线程安全问题怎么解决”吧!1.线程安全概述1.1什么是线程安全问题首先我们需要
    2023-06-30

    MFC多线程传参问题怎么解决

    本篇内容主要讲解“MFC多线程传参问题怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“MFC多线程传参问题怎么解决”吧!在一个程序中,这些独立运行的程序片断叫作“线程”(Thread),利
    2023-06-17

    golang map线程安全问题怎么解决

    在Go语言中,Map是并发不安全的,如果多个goroutine同时对同一个Map进行读写操作,可能会导致数据竞争问题。为了解决Map的线程安全问题,可以采用以下方法:使用互斥锁(Mutex):在对Map进行读写操作之前,先获取锁,操作完成
    golang map线程安全问题怎么解决
    2024-02-29

    Python之ThreadPoolExecutor线程池问题怎么解决

    本文小编为大家详细介绍“Python之ThreadPoolExecutor线程池问题怎么解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“Python之ThreadPoolExecutor线程池问题怎么解决”文章能帮助大家解决疑惑,下面跟
    2023-07-05

    java treemap线程安全问题怎么解决

    要解决Java TreeMap的线程安全问题,有以下几种方法:1. 使用Collections.synchronizedMap()方法包装TreeMap对象,将其转换为线程安全的Map对象。示例代码如下:Map synchronizedMa
    2023-10-20

    Java多线程死锁问题怎么解决

    解决Java多线程死锁问题的常用方法有以下几种:1. 避免使用多个锁:尽量减少使用多个锁来降低出现死锁的概率。2. 按照固定的顺序获取锁:对于多个锁的获取,确保线程按照固定的顺序获取锁,避免出现循环等待的情况。3. 设置超时时间:在获取锁的
    2023-09-22

    Python互斥锁怎么解决多线程问题

    这篇文章给大家分享的是有关Python互斥锁怎么解决多线程问题的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。python主要应用领域有哪些1、云计算,典型应用OpenStack。2、WEB前端开发,众多大型网站均
    2023-06-14

    Python线程怎么解决共享变量问题

    这篇文章主要介绍“Python线程怎么解决共享变量问题”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Python线程怎么解决共享变量问题”文章能帮助大家解决问题。下面展示另一种转账的方式:impor
    2023-06-29

    springboot多线程高并发问题怎么解决

    要解决Spring Boot多线程高并发问题,你可以考虑以下几个方面:1. 线程池配置:合理配置线程池的大小、队列容量等参数,以满足高并发场景下的需求。可以使用Spring Boot提供的线程池配置方式,如通过在application.pr
    2023-08-24

    python多线程效率低问题怎么解决

    Python中的多线程效率低的问题主要是由于Python的全局解释器锁(GIL)导致的。GIL是Python解释器中的一个机制,它确保同一时刻只有一个线程执行Python字节码。要解决Python多线程效率低的问题,可以考虑以下几种方法:1
    2023-09-04

    Java SimpleDateFormat线程不安全问题怎么解决

    本篇内容主要讲解“Java SimpleDateFormat线程不安全问题怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java SimpleDateFormat线程不安全问题怎么解决”
    2023-07-05

    web前端跨域问题怎么解决

    本文小编为大家详细介绍“web前端跨域问题怎么解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“web前端跨域问题怎么解决”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。为什么跨域?为什么会出现跨域问题呢?那就不
    2023-06-29

    vue3 keepalive线上问题怎么解决

    1、keepalive功能keepalive是vue3中的一个全局组件keepalive本身不会渲染出来,也不会出现在dom节点当中,但是它会被渲染为vnode,通过vnode可以跟踪到keepalive中的cache和keys,当然也是在开发环境才可以,build打包以后没有暴露到vnode中(这个还要再确认一下)keepalive最重要的功能就是缓存组件keepalive通过LRU缓存淘汰策略来更新组件缓存,可以更有效的利用内存,防止内存溢出,源代码中的最大缓存数max为10,也就是10个组
    2023-05-19

    java怎么使用多线程解决主线程提前结束问题

    这篇文章主要介绍“java怎么使用多线程解决主线程提前结束问题”,在日常操作中,相信很多人在java怎么使用多线程解决主线程提前结束问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java怎么使用多线程解决
    2023-07-05

    arduino无线循环问题怎么解决

    要解决Arduino无线循环问题,可以考虑以下几个方面:1. 检查代码逻辑:仔细检查代码中的循环语句,确保没有出现无限循环的情况。如果有,可以通过添加退出条件或修改循环逻辑来解决。2. 调试输出:使用Serial.print()或Seria
    2023-08-20

    SpringBoot中的Scheduled单线程执行问题怎么解决

    本篇内容主要讲解“SpringBoot中的Scheduled单线程执行问题怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“SpringBoot中的Scheduled单线程执行问题怎么解决”
    2023-07-02

    Java线程技术中的死锁问题怎么解决

    这篇文章主要介绍“Java线程技术中的死锁问题怎么解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java线程技术中的死锁问题怎么解决”文章能帮助大家解决问题。我们知道,使用 synchroniz
    2023-06-02

    编程热搜

    • Python 学习之路 - Python
      一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
      Python 学习之路 - Python
    • chatgpt的中文全称是什么
      chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
      chatgpt的中文全称是什么
    • C/C++中extern函数使用详解
    • C/C++可变参数的使用
      可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
      C/C++可变参数的使用
    • css样式文件该放在哪里
    • php中数组下标必须是连续的吗
    • Python 3 教程
      Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
      Python 3 教程
    • Python pip包管理
      一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
      Python pip包管理
    • ubuntu如何重新编译内核
    • 改善Java代码之慎用java动态编译

    目录