利用本地 Express Web 服务解决复杂的 Electron 通信链路的问题
背景
Web 服务对前端同学来说并不陌生,你们开发其他前端界面请求的后端接口就是 Web 服务,你们 npm run dev
启动的也是一个本地的 Web 服务,前端的 js,html,css 都有从这个服务上拉取到的资源。
我们在开发 Electron 时发现了 Electron 进程间通信(IPC)的弊端,弊端的主要来源是 webview 到 Main 的通信链路过长,需要从 page 发到 proload.js 文件,再从 preload 发到 render,再从 render 发送到 Main,这个过程中,需要反复定义类同命名的事件进行中转,大大降低了开发效率,还无意中增加了 render 进程的内存耗费。
ipcRenderer 通信知识补充
官网链接:ipcRenderer | Electron
ipcRenderer.send(channel, ...args)
-
描述:从渲染进程向主进程发送异步消息。
-
特点:
-
单向通信,主进程通过 ipcMain.on 监听并处理消息。
-
不会自动返回响应,主进程需要额外的机制(如再次发送消息)来回复渲染进程。
-
-
使用场景:
-
当渲染进程需要通知主进程执行某项操作,且不需要等待结果时。
-
-
示例:
-
通知主进程保存数据、打开新窗口或执行某些后台任务。
-
-
代码示例:
// 渲染进程
ipcRenderer.send('save-data', { key: 'value' });// 主进程
ipcMain.on('save-data', (event, data) => {console.log('收到数据:', data);
});
2. ipcRenderer.invoke(channel, ...args)
-
描述:从渲染进程向主进程发送消息,并等待主进程的响应。
-
特点:
-
异步双向通信,返回一个 Promise,可以通过 await 获取主进程的处理结果。
-
主进程使用 ipcMain.handle 来处理请求并返回数据。
-
-
使用场景:
-
当渲染进程需要从主进程获取数据或等待某个操作完成时。
-
-
示例:
-
获取文件内容、查询数据库结果或执行耗时操作。
-
-
代码示例:
// 渲染进程
async function getFileContent() {const content = await ipcRenderer.invoke('get-file', 'file.txt');console.log('文件内容:', content);
}// 主进程
ipcMain.handle('get-file', async (event, filename) => {return '文件内容示例';
});
3. ipcRenderer.sendSync(channel, ...args)
-
描述:从渲染进程向主进程发送同步消息。
-
特点:
-
会阻塞渲染进程,直到主进程通过 event.returnValue 返回结果。
-
同步操作会影响渲染进程的性能,可能导致 UI 卡顿。
-
-
使用场景:
-
当需要立即获取主进程的响应,且操作足够快时。
-
不推荐广泛使用,因为阻塞 UI 线程会降低用户体验。
-
-
示例:
-
获取简单的配置值或状态。
-
-
代码示例:
// 渲染进程
const result = ipcRenderer.sendSync('get-config', 'theme');
console.log('配置:', result);// 主进程
ipcMain.on('get-config', (event, key) => {event.returnValue = 'dark';
});
4. ipcRenderer.sendTo(webContentsId, channel, ...args)
-
描述:从一个渲染进程向另一个渲染进程发送消息。
-
特点:
-
需要知道目标渲染进程的 webContentsId。
-
消息直接发送到指定的渲染进程,不经过主进程。
-
-
使用场景:
-
当应用有多个窗口或 webview 时,需要在不同渲染进程之间直接通信。
-
-
示例:
-
一个窗口控制另一个窗口的行为或状态。
-
-
代码示例:
// 渲染进程 A
ipcRenderer.sendTo(2, 'update-status', 'ready'); // 2 是目标窗口的 webContentsId// 渲染进程 B
ipcRenderer.on('update-status', (event, status) => {console.log('状态更新:', status);
});
5. ipcRenderer.sendToHost(channel, ...args)
-
描述:从 webview 的渲染进程向其宿主窗口的渲染进程发送消息。
-
特点:
-
特定于 webview 场景,消息发送到宿主窗口的渲染进程,而不是主进程。
-
宿主窗口通过 webview 标签的 on-ipc-message 事件接收消息。
-
-
使用场景:
-
当 webview 内部的代码需要与宿主窗口通信时。
-
-
示例:
-
webview 中的页面通知宿主窗口某个事件发生。
-
-
代码示例:
// webview 中的渲染进程
ipcRenderer.sendToHost('page-event', 'loaded');// 宿主窗口的渲染进程
document.querySelector('webview').addEventListener('ipc-message', (event) => {console.log('收到 webview 消息:', event.args);
});
总结对比
函数名 | 通信方向 | 是否异步 | 返回值 | 推荐场景 |
send | 渲染进程 → 主进程 | 是 | 无 | 单向通知,无需返回结果 |
invoke | 渲染进程 → 主进程 | 是 | Promise | 双向通信,需等待主进程返回数据 |
sendSync | 渲染进程 → 主进程 | 否 | 同步返回值 | 快速同步操作(不推荐,易阻塞 UI) |
sendTo | 渲染进程 → 另一渲染进程 | 是 | 无 | 多窗口或多渲染进程通信 |
sendToHost | webview → 宿主渲染进程 | 是 | 无 | webview 与宿主窗口通信 |
ipcRenderer.sendToHost 详解
这个是最复杂的,但是官网却是讲得最简单的,也没有举例子,外国人做事真得没的说
-
必须结合 preload.js 来实现中转通信,webview 不能直接与主渲染进程通信,至少从 electron 提供的官方文档里面是没有;
-
需要借助 webview 注入脚本的 window.postMessage 向 preload.js 中的 window.addEventListener('message', (event) 进行中转
-
需要 webview dom 对象本身才能收到来自 webview 里面发过来的消息
下面是 webview 与主进程通信的整个链路,使用 await 进行阻塞式等待的解决方案
webview 实现对 Main 进程的 await 请求
通信流程概述
-
webview 页面通过 postMessage 发送请求。
-
预加载脚本捕获请求并通过 ipcRenderer.sendToHost 转发给宿主渲染进程。
-
宿主渲染进程使用 ipcRenderer.invoke 向主进程发送请求并等待响应。
-
主进程通过 ipcMain.handle 处理请求并返回结果。
-
宿主渲染进程收到响应后,通过 webview.send 将结果发送回 webview。
-
预加载脚本通过 postMessage 将响应传递给 webview 页面。
-
webview 页面中的 Promise 解析,获取响应数据。
时序图
通信流程具体实现细节
1. webview 内部页面发送请求并等待响应
在 webview 的页面中,使用 postMessage 发送请求,并通过事件监听接收响应,利用 Promise 和 await 实现异步等待。
html
<!-- webview.html -->
<script>async function sendRequest(data) {// 发送请求window.postMessage({ type: 'async-request', data }, '*');// 等待响应return new Promise((resolve) => {window.addEventListener('message', function handler(event) {if (event.data.type === 'async-response') {window.removeEventListener('message', handler);resolve(event.data.response);}});});}// 示例:调用并等待响应(async () => {const response = await sendRequest('一些数据');console.log('收到响应:', response);})();
</script>
2. webview 的预加载脚本
在预加载脚本中,监听 webview 的消息并通过 ipcRenderer.sendToHost 转发给宿主渲染进程,同时接收响应并传递回 webview。
// preload.js
const { ipcRenderer } = require('electron');window.addEventListener('message', (event) => {if (event.data.type === 'async-request') {// 转发请求到宿主渲染进程ipcRenderer.sendToHost('async-request', event.data.data);}
});// 接收宿主渲染进程的响应
ipcRenderer.on('async-response', (event, response) => {window.postMessage({ type: 'async-response', response }, '*');
});
3. 宿主渲染进程处理请求
在宿主渲染进程中,监听 webview 的消息,使用 ipcRenderer.invoke 向主进程发送请求并等待响应,之后将结果发送回 webview。
// renderer.js (宿主渲染进程)
const { ipcRenderer } = require('electron');
const webview = document.querySelector('webview');webview.addEventListener('ipc-message', async (event) => {if (event.channel === 'async-request') {try {// 使用 await 等待主进程响应const response = await ipcRenderer.invoke('async-to-main', event.args[0]);// 将响应发送回 webviewwebview.send('async-response', response);} catch (error) {console.error('请求失败:', error);}}
});
4. 主进程处理请求
在主进程中,使用 ipcMain.handle 处理来自渲染进程的请求,并返回一个 Promise 作为响应。
// main.js
const { ipcMain } = require('electron');ipcMain.handle('async-to-main', async (event, data) => {console.log('收到异步请求:', data);// 模拟异步操作,例如文件读取或延时await new Promise((resolve) => setTimeout(resolve, 1000));return '处理后的数据';
});
5. 宿主页面配置
在宿主渲染进程的 HTML 文件中,正确加载 webview 并指定预加载脚本。
<!-- index.html -->
<webview src="./webview.html" preload="./preload.js"></webview>
引入 web 服务的好处
-
可以将以上过程减少为一次本地的 http 请求
实现过程
1. 项目准备
确保你已经初始化了一个 Electron 项目。如果没有,可以按照以下步骤快速创建一个:
mkdir electron-express-example
cd electron-express-example
npm init -y
npm install electron express cors
项目结构如下
electron-express-example/
├── main.js # 主进程文件
├── index.html # webview 页面
├── package.json
└── node_modules/
2. 在主进程中引入并配置 Express
在 main.js 文件中,我们将引入 Express,启动一个简单的服务器,并定义一个路由来返回配置信息。同时,我们需要处理 Electron 的窗口创建。
以下是 main.js 的完整代码:
const { app, BrowserWindow } = require('electron');
const express = require('express');
const cors = require('cors');let mainWindow;// 创建 Express 应用
const expressApp = express();
expressApp.use(cors()); // 解决跨域问题// 定义一个 /config 路由,返回配置信息
expressApp.get('/config', (req, res) => {res.json({ config: '这是来自主进程的配置信息' });
});// 启动 Express 服务器
expressApp.listen(3000, () => {console.log('Express server running on port 3000');
});// Electron 应用启动
app.on('ready', () => {// 创建主窗口mainWindow = new BrowserWindow({width: 800,height: 600,webPreferences: {webviewTag: true // 启用 webview 标签}});// 加载包含 webview 的页面mainWindow.loadFile('index.html');
});// 应用退出时清理
app.on('window-all-closed', () => {if (process.platform !== 'darwin') {app.quit();}
});
说明:
-
我们引入了 express 和 cors,并在 3000 端口启动了一个 Express 服务器。
-
/config 路由返回一个简单的 JSON 对象,包含配置信息。
-
使用 cors 中间件解决 webview 请求时的跨域问题。
-
Electron 的主窗口加载了一个 index.html 文件,里面会包含 webview。
3. 创建 webview 页面
在 index.html 中,我们使用 <webview> 标签加载一个简单的页面,并在页面中通过 fetch 请求主进程的 Express 服务获取配置信息。
以下是 index.html 的代码:
<!DOCTYPE html>
<html>
<head><title>Electron Webview Example</title>
</head>
<body><h1>Electron Webview 与主进程通信</h1><webview id="myWebview" src="data:text/html"><html><body><h2>Webview 内容</h2><p>配置信息: <span id='configDisplay'>加载中...</span></p><script>const res = await fetch('http://localhost:3000/config')const data = await res.json()</script></body></html>"style="width: 600px; height: 400px;"></webview>
</body>
</html>
Web服务框架简介
-
什么是Web服务框架?
Web服务框架是用于构建和管理Web服务的工具或库,通常用于创建HTTP API。它提供路由管理、请求处理和响应生成的功能,帮助开发者快速搭建服务器端应用。 -
为什么前端开发者需要了解Web服务框架?
-
接口交互:前端界面依赖后端Web服务提供数据,理解其原理有助于优化请求设计。
-
本地开发:运行npm run dev时启动的本地服务(如Webpack Dev Server)本质上也是Web服务,前端资源(如JS、HTML、CSS)从中加载。
-
项目需求:在快速原型开发或Electron等场景中,前端开发者可能需要独立实现简单的后台服务。
-
-
Web服务框架在现代开发中的作用
-
提供RESTful API或GraphQL服务,支撑前端应用。
-
处理用户请求、业务逻辑和数据交互。
-
2. Node.js Web服务框架
-
为什么选择Node.js?
-
前端开发者熟悉JavaScript,Node.js让前后端开发语言统一,降低学习成本。
-
拥有丰富的npm生态和强大的社区支持。
-
-
流行的Node.js Web服务框架
-
Express.js
-
优点:简单易用、灵活性高、社区资源丰富。
-
适用场景:快速原型、小型到中型项目。
-
-
Koa.js
-
优点:支持async/await,代码更简洁,性能优化。
-
适用场景:现代化项目、注重代码可维护性。
-
-
Hapi.js
-
优点:强大的输入验证和配置驱动设计。
-
适用场景:需要高安全性的API开发。
-
-
Nest.js
-
优点:模块化、依赖注入,适合复杂应用。
-
适用场景:大型项目、有Angular经验的开发者。
-
-
Fastify
-
优点:高性能、低开销。
-
适用场景:高流量服务、微服务架构。
-
-
3. 在Electron中应用Web服务框架
-
Electron的IPC通信及其弊端
-
机制:IPC用于主进程(Main)和渲染进程(Renderer)之间的通信。
-
弊端:
-
通信链路过长:从页面 → preload.js → 渲染进程 → 主进程,需要多次中转。
-
开发效率低:反复定义事件(如ipcRenderer.send和ipcMain.on)增加代码复杂性。
-
内存消耗高:渲染进程因事件监听和中转逻辑占用更多资源。
-
-
-
在主进程中运行Web服务框架
-
在主进程中启动一个本地HTTP服务器(如Express.js)。
-
渲染进程通过HTTP请求(如fetch)与主进程通信,替代IPC。
-
-
HTTP请求替代IPC的优缺点
-
优点:
-
熟悉性:前端开发者习惯使用HTTP请求。
-
调试方便:可通过浏览器开发者工具查看请求。
-
逻辑清晰:主进程专注服务端,渲染进程专注UI。
-
-
缺点:
-
性能开销:HTTP比IPC多了网络层开销。
-
复杂性:简单通信任务可能不需要服务器。
-
-
-
代码示例
-
主进程中设置Express服务器:
-
const express = require('express');
const { app } = require('electron');
const server = express();server.get('/api/message', (req, res) => {res.json({ message: 'Hello from Main Process!' });
});app.on('ready', () => {server.listen(3000, () => {console.log('Server running on port 3000');});
});
-
渲染进程中调用:
<script>fetch('http://localhost:3000/api/message').then(response => response.json()).then(data => console.log(data.message)).catch(error => console.error('Error:', error));
</script>
4. 性能与安全性权衡
-
HTTP请求与IPC的性能比较
-
IPC:直接进程通信,延迟低,适合简单任务。
-
HTTP:涉及网络栈,延迟稍高,但更灵活。
-
-
安全性考虑
-
CORS:需配置跨源资源共享以允许渲染进程访问。
-
const cors = require('cors');
server.use(cors());
-
验证:建议添加令牌或IP限制,确保请求来源可信。
-
适用场景
-
IPC适合轻量级通信,HTTP适合复杂数据交互或开发者更熟悉的场景。
5. 如何选择合适的Web服务框架
-
选择时的考虑因素
-
性能:Fastify适合高性能需求,Express适合一般场景。
-
易用性:Express和Koa上手快,Nest学习曲线较陡。
-
社区支持:Express生态最成熟,Fastify较新。
-
项目规模:小型项目用Express,大型项目考虑Nest。
-
-
在Electron中的推荐
-
Express.js因其简单性和广泛支持,适合初学者和大多数场景。
-
根据需求权衡是否需要更高性能(如Fastify)。
-
-
学习建议
-
从Express.js入门,逐步尝试Koa或Fastify。
-
通过实践项目(如构建一个简单的API)巩固知识。
-
相关文章:
利用本地 Express Web 服务解决复杂的 Electron 通信链路的问题
背景 Web 服务对前端同学来说并不陌生,你们开发其他前端界面请求的后端接口就是 Web 服务,你们 npm run dev启动的也是一个本地的 Web 服务,前端的 js,html,css 都有从这个服务上拉取到的资源。 我们在开发 Electron…...
《自然-计算科学》诚邀您投稿计算社会科学研究(computational social science)
李升伟 编译 近年来,运用计算方法和工具来深化对社会科学长期议题理解的"计算社会科学"发展迅猛。这一增长主要得益于社交媒体数据、移动通信数据、数字化图书与历史档案、医疗记录等海量数据的涌现,这些资源不仅为验证现有社会科学理论提供了…...
【SPSS/EXCEl】主成分分析构建__综合评价指数
学习过程中实验操作的记录 1.数据准备和标准化: (1)区分正负相关性:判断每个因子是正向指标还是负向指标,计算每个的最大值和最小值 (2) 标准化: Min-Max标准化 Min-Max标准化(最大最小值法): 将数据映射到指定的区间ÿ…...
#node.js后端项目的部署相关了解
熟悉 Spring Boot 的 java -jar 启动方式,那咱们就用类比 实战方式,来彻底搞懂: 🚀 Node.js 后端项目的 部署 & 启动方式 ✅ 和 Spring Boot 的 java -jar xxx.jar 一样,Node.js 也可以一句命令启动,而…...
程序化广告行业(69/89):DMP与PCP系统核心功能剖析
程序化广告行业(69/89):DMP与PCP系统核心功能剖析 在数字化营销浪潮中,程序化广告已成为企业精准触达目标受众的关键手段。作为行业探索者,我深知其中知识的繁杂与重要性。一直以来,都希望能和大家一同学习…...
基于Python的二手房数据挖掘与可视化深度分析
一、技术框架与数据概况 1.1 技术栈构成 import pandas as pd # 数据操作(v1.3.5) import numpy as np # 数值计算(v1.21.6) from pyecharts.charts import * # 交互式可视化(v1.9.1) from sklearn.preprocessing import StandardScaler # 数据标准化(可选扩展) …...
linux第三次作业
1、将你的虚拟机的网卡模式设置为nat模式,给虚拟机网卡配置三个主机位分别为100、200、168的ip地址 2、测试你的虚拟机是否能够ping通网关和dns,如果不能请修改网关和dns的地址 3、将如下内容写入/etc/hosts文件中(如果有多个ip地址则写多行&…...
C#编写HttpClient爬虫程序示例
要写一个使用C#和HttpClient的爬虫程序。首先,我需要了解HttpClient的基本用法。HttpClient是用来发送HTTP请求和接收响应的类,对吧?我记得在C#中使用它的时候需要注意一些事情,比如最好使用单例实例,而不是频繁创建和…...
关于Spring MVC在无注解情况下通过参数名匹配获取请求参数的详细说明,包含代码示例和总结表格
以下是关于Spring MVC在无注解情况下通过参数名匹配获取请求参数的详细说明,包含代码示例和总结表格: 1. 核心机制 Spring MVC通过参数名匹配实现无注解参数绑定: 条件:方法参数名需与请求参数(查询参数、表单参数&a…...
数智读书笔记系列027:《医疗健康大数据治理》构建智慧医疗的核心基石
一、图书介绍: 1.1 书籍基本信息 在当今数字化技术飞速发展的背景下,医疗行业正经历着前所未有的变革。信息化、智能化、数据驱动的趋势正在深入到医疗服务的各个环节,推动着医疗健康大数据成为医疗行业发展的核心资产。在这样的时代背景下,《医疗健康大数据治理》这本书应…...
Wayland介绍
Wayland 是一种现代化的显示服务器协议,旨在替代传统的 X Window System(X11),为 Linux 和类 Unix 系统提供更高效、安全的图形显示管理。以下是其核心要点: 1. 基本概念 显示服务器协议:Wayland 定义了客户…...
dockerTeskTop安装dify及使用deepseek
配置 在这之前,要把模型运行一起,我这里是 PS C:\Users\Administrator> ollama run deepseek-r1:8b 模型名称一定要写对 如果添加失败,参考 dify 1.0.1无法在ollama下新增LLM模型 - 何辉煌 - 博客园...
解释 Git 的基本概念和使用方式
Git 是一个分布式版本控制系统,用于跟踪文件的变化并协作开发项目。下面是 Git 的一些基本概念和使用方式: 仓库(Repository):Git 仓库是用来存储项目文件的地方,可以在本地计算机上创建一个本地仓库&#…...
【区块链安全 | 第三十三篇】备忘单
文章目录 备忘单操作符优先级备忘单ABI 编码和解码函数bytes 和 string 的成员Address 的成员区块与交易属性校验和断言数学和加密函数合约相关类型信息函数可见性说明符修饰符备忘单 操作符优先级备忘单 以下是操作符的优先级顺序,按评估顺序列出: 优先级描述操作符1后缀递…...
MyBatis的缓存、逆向工程、使用PageHelper、使用PageHelper
一、MyBatis的缓存 缓存:cache 缓存的作用:通过减少IO的方式,来提高程序的执行效率。 mybatis的缓存:将select语句的查询结果放到缓存(内存)当中,下一次还是这条select语句的话,直…...
GS+:地统计分析与空间插值工具
大家好,今天为大家介绍的软件是GS:一款用于地统计分析与空间数据处理的软件。与ArcGIS相比的话,它更适合专注于地质统计学分析的用户,尤其是需要对半方差函数进行深入分析和调整的场景下面。我们将从软件的主要功能、支持的系统、…...
C++类型转换详解
目录 一、内置 转 内置 二、内置 转 自定义 三、自定义 转 内置 四、自定义 转 自定义 五、类型转换规范化 1.static_case 2.reinterpret_cast 3.const_cast 4.dynamic_cast 六、RTTI 一、内置 转 内置 C兼容C语言,在内置类型之间转换规则和C语言一样的&am…...
scala-集合2
可变数组 定义变长数组 val arr01 ArrayBuffer[Any](3, 2, 5) (1)[Any]存放任意数据类型 (2)(3, 2, 5)初始化好的三个元素 (3)ArrayBuffer 需要引入 scala.collection.mutable.ArrayBuffer 案例实操 Arra…...
Clang编译器优化选项
Clang 作为 C/C 编译器,提供了丰富的优化选项,以下是主要的优化相关选项分类和说明: 1. 优化级别(通用选项) 选项说明-O0默认级别,禁用所有优化,用于调试。-O1基础优化(代码大小和执…...
Java文件流操作 - 【Guava】IO工具
引言 Guava 使用术语 流来表示可关闭的,并且在底层资源中有位置状态的 I/O 数据流。字节流对应的工具类为 ByteSterams,字符流对应的工具类为 CharStreams。 Guava 中为了避免和流直接打交道,抽象出可读的 源 source 和可写的 汇 sink 两个概…...
C语言中单链表操作:查找节点与删除节点
一. 简介 前面学习了C语言中创建链表节点,向链表中插入节点等操作,文章如下: C语言中单向链表:创建节点与插入新节点-CSDN博客 本文继续学习c语言中对链表的其他操作,例如在链表中查找某个节点,删除链表…...
mapbox基础,加载栅格图片到地图
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️raster 栅格图层 api二、🍀使用本地载…...
Linux红帽:RHCSA认证知识讲解(十 二)调试 SELinux,如何管理 SELinux 的运行模式、安全策略、端口和上下文策略
Linux红帽:RHCSA认证知识讲解(十 二)调试 SELinux,如何管理 SELinux 的运行模式、安全策略、端口和上下文策略 前言一、SELinux 简介二、SELinux 的运行模式2.1 查看和切换 SELinux 模式 三、SELinux 预设安全策略的开关控制四、管…...
模糊斜率熵Fuzzy Slope entropy+状态分类识别!2024年11月新作登上IEEE Trans顶刊
引言 2024年11月,研究者在测量领域国际顶级期刊《IEEE Transactions on Instrumentation and Measurement》(IF 5.6,JCR 1区,中科院二区)上发表科学研究成果,以“Optimized Fuzzy Slope Entropy: A Comple…...
【MATLAB】将数据保存在mat文件中 save/load/matfile
MAT文件为MATLAB格式的二进制文件 save()函数 save - 将工作区变量保存到文件中 save(filename) 将当前工作区中的所有变量保存在 MATLAB 格式的二进制文件(MAT 文件)filename 中。如果 filename 已存在,save 会覆盖该文件。 save(filena…...
009_抽象类和接口
抽象类和接口 final关键字常量 单例模式(设计模式)枚举类抽象类抽象类的注意事项、特点使用抽象类的好处模版方法设计模式 接口接口的好处接口的注意事项 final关键字 final关键字是最终的意思,可以修饰类、方法、变量。 修饰类:…...
【数据结构】排序算法(下篇·开端)·深剖数据难点
前引:前面我们通过层层学习,也就了解了Hoare大佬的排序思想,今天我们学习的东西可能稍微有点难度,因此我们必须学会思想,我很受感慨,因此借此分享一下:【用1520分钟去调试】,如果我们…...
Elixir语言的计算机视觉
Elixir语言在计算机视觉中的应用 引言 计算机视觉作为一门交叉学科,近年来随着深度学习技术的发展而蓬勃发展。传统上,计算机视觉应用通常采用Python、C等语言进行开发,因为这些语言拥有强大的图像处理库和深度学习框架。然而,随…...
VTK知识学习(51)- 交互与Widget(二)
1、交互器样式 前面所讲的观察者/命令模式是 VTK实现交互的方式之一。在前面示例 所示的窗口中可以使用鼠标与柱体进行交互,比如用鼠标滚轮可以对柱体放大、缩小;按下鼠标左键不放,然后移动鼠标,可以转动柱体;按下鼠标左键,同时按…...
目标跟踪Deepsort算法学习2025.4.7
一.DeepSORT概述 1.1 算法定义 DeepSORT(Deep Learning and Sorting)是一种先进的多目标跟踪算法,它结合了深度学习和传统的目标跟踪技术,在复杂环境下实现了高精度和鲁棒性的目标跟踪。该算法的核心思想是通过融合目标的外观特征和运动特征,实现对多个目标的持续跟踪,…...
nacos集群启动问题
根据您的描述,Nacos集群只能启动两个节点,可能的原因和解决方法如下: 1. 集群配置问题 • 原因:cluster.conf文件中可能只配置了两个节点的地址,导致第三个节点无法加入集群。 • 解决方法: • 检查每个…...
八大排序——c++版
本次排序都是按照升序排的 冒泡排序 void bubbleSort(vector<int>& nums) {int nnums.size();for(int i0;i<n-1;i){bool swappedfalse;for(int j0;j<n-1-i;j){if(nums[j]>nums[j1]){swap(nums[j],nums[j1]);swappedtrue;}}if(!swapped)break;} } //算法原…...
关于Spring MVC中传递数组参数的详细说明,包括如何通过逗号分隔的字符串自动转换为数组,以及具体的代码示例和总结表格
以下是关于Spring MVC中传递数组参数的详细说明,包括如何通过逗号分隔的字符串自动转换为数组,以及具体的代码示例和总结表格: 1. 核心机制 Spring MVC支持直接通过逗号分隔的字符串将请求参数自动转换为数组(String[]、int[]等&…...
VBA之Word应用:利用Range方法进行字体及对齐方式设置
《VBA之Word应用》(版权10178982),是我推出第八套教程,教程是专门讲解VBA在Word中的应用,围绕“面向对象编程”讲解,首先让大家认识Word中VBA的对象,以及对象的属性、方法,然后通过实…...
区块链技术:重塑供应链管理的未来
在当今全球化的商业环境中,供应链管理的复杂性和重要性日益凸显。从原材料采购到产品交付,供应链的每一个环节都可能影响企业的运营效率和客户满意度。随着区块链技术的兴起,供应链管理迎来了新的变革机遇。本文将深入探讨区块链技术在供应链…...
请回答集成测试和系统测试的区别,以及它们的应用场景主要是什么?
导语: 深夜收到粉丝私信:"面了5家大厂,4家都问集成测试和系统测试的区别,求大佬支招!" 作为经历过200+项目实战的测试老司机,今天用4个真实项目案例+3张原理图,带你彻底吃透这两个核心测试阶段!(文末送测试用例模板) 一、灵魂三问:到底测什么? 1.1 集成…...
SVT-AV1学习-svt_aom_get_sg_filter_level,svt_av1_selfguided_restoration_c
SVT-AV1学习-svt_aom_get_sg_filter_level,svt_av1_selfguided_restoration_c 一 函数的作用 根据编码模式,输入分辨率和快速解码标志动态计算自引导恢复(Self Guide Restoration)过滤器的启动级别,以下是详细解析; 1 参数说明 EncMode enc_m…...
第七章总结:集合
一、集合简介 Scala集合分为三大类:序列(Seq)、集(Set)、映射(Map),所有集合都扩展自Iterable特质。集合分为可变集合和不可变集合: 不可变集合:scala.collec…...
玄机靶场:apache日志分析
什么是Apache日志 Apache日志是Apache Web服务器在处理HTTP请求时记录的所有事件的详细信息。Apache是全球最受欢迎的Web服务器软件之一,支持约30.2%的所有活跃网站。Apache通过记录每次请求的信息,包括时间、来源IP、请求的资源等,帮助分…...
Laravel 使用 事件和监听器实现 数据状态变更
首先知道事件是什么 1.事件的概念 事件(Event)是 Laravel 中实现观察者模式的一种机制,它允许应用程序中的不同部分进行松耦合的通信。 通俗一点就是,发生在应用程序中的动作或者事情。例如: 用户注册成功后,需要发邮件&#…...
uniapp App页面通过 web-view 调用网页内方法
先是报这个错 A parser-blocking, cross site (i.e. different eTLD1) script, https://api.map.baidu.com/getscript?v3.0&akpgJsRF87Fjia&services&t20250225111334, is invoked via document.write. The network request for this script MAY be blocked by t…...
Daz3D角色UE5材质优化
解决Daz3D人物角色导入UE5后材质不真实的问题 1. 引言:跨平台3D资产传输中的材质保真度挑战 在当今的数字内容创作领域,对高质量3D人物角色的需求日益增长,广泛应用于游戏开发、电影制作、虚拟现实等多种应用场景。Daz3D因其丰富的人物模型…...
Android studio
问题:没有界面可以操作,页面没有hello wolrd 原因:gradle没同步完,依赖项没有下载完整,所以布局预览看不了...
Playwright快照测试:如何让UI回归测试变得轻松高效
引言 使用带有模拟数据的PlaywrightP快照可以显著提高UI回归测试的速度。它能够快速自动化检查三大主流浏览器(Chromium、Firefox、Webkit)中的 UI 元素。你可以将多个断言绑定到一个快照上,这极大地提高了 UI 测试的效率。在 GUI 应用快速扩…...
控制理论-传递函数
【硬核】终于有人把传递函数和卷积定理讲明白了!自动控制原理入门-传递函数 | 卷积定理 | 频率响应 | 喵星考拉...
虚拟世界的AI魔法:AIGC引领元宇宙创作革命
云边有个稻草人-CSDN博客——个人主页 热门文章_云边有个稻草人的博客-CSDN博客——本篇文章所属专栏 ~ 欢迎订阅~ 目录 1. 引言 2. 元宇宙与虚拟世界概述 2.1 什么是元宇宙? 2.2 虚拟世界的构建 3. AIGC在元宇宙中的应用 3.1 AIGC生成虚拟世界环境 3.2 AIGC…...
带QT界面的文件管理系统
下载地址 下载&完整介绍地址:https://www.mcso.top/course-design/qt-filesystem/ 开源地址:https://github.com/mcdudu233/FileSystem.git 软件包含 (1)设计数据的结构 (2)设计文件管理系统 &…...
【区块链安全 | 第二十六篇】表达式与控制结构(二)
文章目录 表达式与控制结构赋值结构化赋值与返回多个值数组和结构体的赋值复杂性作用域和声明检查或不检查的算术运算错误处理:Assert、Require、Revert 和异常通过 assert 进行 Panic 和通过 require 进行 Errorreverttry/catch表达式与控制结构 赋值 结构化赋值与返回多个…...
2025年前端框架全景解析:React、Vue、Angular的生态与未来之争
一、市场格局:全球与国内的双重差异12 全球市场React:凭借Facebook的支持和庞大的社区,全球使用率超40%,尤其在数据密集型应用(如金融、社交平台)中占据主导。其跨平台能力(React Native)和灵活生态(Next.js、Redux)是核心竞争力。Vue:亚洲市场占比显著,中国开发者…...
【VScode】C/C++使用教程
编辑器 1. VScode本质上是一款代码编辑器,上面包含了许多插件。 VScode下载 1. 下载链接:Download Visual Studio Code - Mac, Linux, Windowshttps://code.visualstudio.com/download2. 在拓展部分下载汉化包:Chinese。 编译器 1. 我们使用M…...