PageSourceSearch

https://lolipopj.github.io/component---src-templates-post-tsx-cont…t-execution-log-mdx-2661816b933944e0c926.js

js lolipopj.github.io collected 2026-10-03 09:33:04 UTC 44,063 bytes, 2 lines download raw bytes

1"use strict";(self.webpackChunkhomepage=self.webpackChunkhomepage||[]).push([[8996],{2643:function(n,s,a){a.r(s),a.d(s,{Head:function(){return v},default:function(){return _}});var t=a(5676),p=a(758);function e(n){const s=Object.assign({p:"p",strong:"strong",h2:"h2",ol:"ol",li:"li",a:"a",h3:"h3",span:"span",img:"img"},(0,t.R)(),n.components);return p.createElement(p.Fragment,null,p.createElement(s.p,null,"开发图像查重工具时遇到了这样一个问题:在查重之前,用户需要先对图像文件进行索引操作,后台将调用可执行文件并为每张图像生成特征值。索引操作所需的时间与图像的数量及大小呈正相关,笔者为大约 50000 张图片(约 170GB)生成特征值,需要花费将近 90 分钟的时间。在这种情况下,如果渲染器什么也不展示,卡在那里,用户难免会非常焦虑 —— 后台是否还在运行,我是不是卡死了?"),"\n",p.createElement(s.p,null,"那么需求也就明了了,正如本文的标题所述,我们需要",p.createElement(s.strong,null,"将后台运行的日志实时推送到渲染器"),",这样用户便能看到索引操作的进度,安下心来。"),"\n",p.createElement(s.h2,null,"技术背景"),"\n",p.createElement(s.p,null,"众所周知,一个 Electron 应用分为了 Renderer 渲染器和 Main 主进程两端。渲染器负责对客侧的展示,正如我们访问的所有网页一样,是 HTML、CSS、JavaScript 的集合,无法调用 Node 或是访问宿主机文件等。而主进程则具备有服务端应用的性质,能够调用 Node 或是与宿主机交互等。"),"\n",p.createElement(s.p,null,"综上所述,为了实现我们的目标,在背后依次要实现这些事情:"),"\n",p.createElement(s.ol,null,"\n",p.createElement(s.li,null,"渲染器接收用户索引操作的请求,将请求发送至主进程。"),"\n",p.createElement(s.li,null,"主进程接收到请求,调用可执行文件开始生成图像特征值。"),"\n",p.createElement(s.li,null,"主进程将产生的日志信息实时推送给渲染器。"),"\n",p.createElement(s.li,null,"渲染器接收到日志信息,并向用户展示。"),"\n"),"\n",p.createElement(s.h2,null,"需求实现"),"\n",p.createElement(s.p,null,"根据刚才的分析,对",p.createElement(s.a,{href:"https://www.electronjs.org/zh/docs/latest/tutorial/ipc"},"进程间通信(Inter-Process Communication,IPC)"),"能力的使用将会是实现需求的关键。"),"\n",p.createElement(s.p,null,"实现的具体方案遵循 Electron 推荐的安全设置即上下文隔离。下面的内容假设您对",p.createElement(s.a,{href:"https://www.electronjs.org/zh/docs/latest/tutorial/process-model#preload-%E8%84%9A%E6%9C%AC"},"预加载器"),"有一定的了解。"),"\n",p.createElement(s.h3,null,"渲染器将请求发送至主进程"),"\n",p.createElement(s.p,null,"渲染器发送请求至主进程是",p.createElement(s.strong,null,"渲染器到主进程的单向通信"),",具体的实现分成三个步骤:"),"\n",p.createElement(s.ol,null,"\n",p.createElement(s.li,null,"\n",p.createElement(s.p,null,"主进程通过 ",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">ipcMain.on()</code>'}})," 监听请求。"),"\n",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="ts"><pre class="language-ts"><code class="language-ts"><span class="token comment">// main/background.ts</span>\n<span class="token keyword">import</span> <span class="token punctuation">{</span> ipcMain <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"electron"</span><span class="token punctuation">;</span>\n\n<span class="token keyword">export</span> <span class="token keyword">enum</span> Events <span class="token punctuation">{</span>\n  <span class="token constant">UPDATE_INDEX</span> <span class="token operator">=</span> <span class="token string">"events:updateIndex"</span><span class="token punctuation">,</span>\n<span class="token punctuation">}</span>\n\nipcMain<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>Events<span class="token punctuation">.</span><span class="token constant">UPDATE_INDEX</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>_<span class="token punctuation">,</span> args<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n  <span class="token comment">// todo: execute binary</span>\n<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div>'}}),"\n"),"\n",p.createElement(s.li,null,"\n",p.createElement(s.p,null,"预加载器向渲染器暴露 ",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">ipcRenderer.send()</code>'}})," 方法。"),"\n",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="ts"><pre class="language-ts"><code class="language-ts"><span class="token comment">// main/preload.ts</span>\n<span class="token keyword">
1import</span> <span class="token punctuation">{</span> ipcRenderer<span class="token punctuation">,</span> contextBridge <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"electron"</span><span class="token punctuation">;</span>\n\n<span class="token keyword">const</span> ipc <span class="token operator">=</span> <span class="token punctuation">{</span>\n  <span class="token function-variable function">send</span><span class="token operator">:</span> <span class="token punctuation">(</span>channel<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token operator">...</span>args<span class="token operator">:</span> <span class="token builtin">unknown</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n    ipcRenderer<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>channel<span class="token punctuation">,</span> <span class="token operator">...</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span>\n  <span class="token punctuation">}</span><span class="token punctuation">,</span>\n  <span class="token comment">// 由于 Electron 的安全机制,您不能直接暴露 `ipcRenderer` 以及上面的方法</span>\n  <span class="token comment">// 错误的例子:</span>\n  <span class="token comment">// send: ipcRenderer.send,</span>\n<span class="token punctuation">}</span><span class="token punctuation">;</span>\n\ncontextBridge<span class="token punctuation">.</span><span class="token function">exposeInMainWorld</span><span class="token punctuation">(</span><span class="token string">"ipc"</span><span class="token punctuation">,</span> ipc<span class="token punctuation">)</span><span class="token punctuation">;</span>\n\n<span class="token keyword">export</span> <span class="token keyword">type</span> <span class="token class-name"><span class="token constant">IPC</span></span> <span class="token operator">=</span> <span class="token keyword">typeof</span> ipc<span class="token punctuation">;</span></code></pre></div>'}}),"\n",p.createElement(s.p,null,"让 TypeScript 更好地为您工作,别忘了将类型 ",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">IPC</code>'}})," 暴露给 ",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">Window</code>'}})," 对象:"),"\n",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="ts"><pre class="language-ts"><code class="language-ts"><span class="token comment">// renderer/preload.d.ts</span>\n<span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">{</span> <span class="token constant">IPC</span> <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"path/to/main/preload"</span><span class="token punctuation">;</span>\n\n<span class="token keyword">declare</span> global <span class="token punctuation">{</span>\n  <span class="token keyword">interface</span> <span class="token class-name">Window</span> <span class="token punctuation">{</span>\n    ipc<span class="token operator">:</span> <span class="token constant">IPC</span><span class="token punctuation">;</span>\n  <span class="token punctuation">}</span>\n<span class="token punctuation">}</span></code></pre></div>'}}),"\n"),"\n",p.createElement(s.li,null,"\n",p.createElement(s.p,null,"渲染器实现调用预加载器暴露的方法。"),"\n",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="tsx"><pre class="language-tsx"><code class="language-tsx"><span class="token comment">// renderer/path/to/component-trigger.tsx</span>\n<span class="token keyword">
1import</span> <span class="token punctuation">{</span> Events <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"path/to/main/background"</span><span class="token punctuation">;</span>\n\n<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n  <span class="token keyword">const</span> <span class="token function-variable function">onUpdateIndex</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n    window<span class="token punctuation">.</span>ipc<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>Events<span class="token punctuation">.</span><span class="token constant">UPDATE_INDEX</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n  <span class="token punctuation">}</span><span class="token punctuation">;</span>\n\n  <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span></span><span class="token punctuation">></span></span><span class="token punctuation">{</span><span class="token comment">/* component details */</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span></span><span class="token punctuation">></span></span><span class="token punctuation">;</span>\n<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre></div>'}}),"\n",p.createElement(s.p,null,"再在合适的地方编写触发逻辑,即可将请求发送至主进程。"),"\n"),"\n"),"\n",p.createElement(s.h3,null,"主进程调用可执行文件"),"\n",p.createElement(s.p,null,"接着,让我们来完善主进程的逻辑:在接收到请求后,去调用本地的可执行文件。"),"\n",p.createElement(s.p,null,"在 Node 环境中,我们可以找老朋友 ",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">child_process</code>'}})," 帮忙。",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">child_process.exec()</code>'}})," 会等待执行结束后将结果一并返回,不满足我们的需要;",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">child_process.spawn()</code>'}})," 采用事件监听机制,可以应对实时输出日志的情景,满足我们的需要。"),"\n",p.createElement(s.p,null,"基于 ",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">child_process.spawn()</code>'}})," 编写代码如下:"),"\n",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="ts"><pre class="language-ts"><code class="language-ts"><span class="token comment">// main/background.ts</span>\n<span class="token keyword">import</span> <span class="token punctuation">{</span> spawn <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"child_process"</span><span class="token punctuation">;</span>\n\n<span class="token keyword">const</span> <span class="token function-variable function">runSpawn</span> <span class="token operator">=</span> <span class="token punctuation">(</span>cmd<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">,</span> args<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n  <span class="token keyword">const</span> process <span class="token operator">=</span> <span class="token function">spawn</span><span class="token punctuation">(</span>cmd<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>\n\n  process<span class="token punctuation">.</span>stdout<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">"data"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>data<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n    <span class="token comment">// todo: on receive stdout data</span>\n  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n\n  process<span class="token punctuation">.</span>stderr<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">"data"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>data<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n    <span class="token comment">// todo: on receive stderr data</span>\n  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n\n  process<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">"close"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>code<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n    <span class="token comment">// todo: on receive close signal</span>\n  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n<span class="token punctuation">}</span><span class="token punctuation">;</span>\n\nipcMain<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>Events<span class="token punctuation">.</span><span class="token constant">UPDATE_INDEX</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>_<span class="token punctuation">,</span> args<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n  <span class="token function">runSpawn</span><span class="token punctuation">(</span><span class="token string">"path/to/binary"</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">"--update-index"</span><span class="token punctuation">,</span> <span class="token string">"--rest-args"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div>'}}),"\n",p.createElement(s.h3,null,"主进程实时推送日志信息给渲染器"),"\n",p.createElement(s.p,null,"当事件监听器触发时,向渲染器发送日志信息,这是",p.createElement(s.strong,null,"主进程到渲染器的单向通信"),",具体的实现同样分成三个步骤:"),"\n",p.createElement(s.ol,null,"\n",p.createElement(s.li,null,"\n",p.createElement(s.p,null,"主进程通过 ",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">browserWindow.webContents.send()</code>'}})," 发送信息。"),"\n",p.createElement(s.p,null,"完善前面的 ",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">runSpawn()</code>'}})," 方法:"),"\n",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="ts"><pre class="language-ts"><code class="language-ts"><span class="token comment">// main/background.ts</span>\n<span class="token keyword">
1import</span> iconv <span class="token keyword">from</span> <span class="token string">"iconv-lite"</span><span class="token punctuation">;</span>\n\n<span class="token keyword">export</span> <span class="token keyword">enum</span> SpawnEvents <span class="token punctuation">{</span>\n  <span class="token constant">SPAWN_STARTED</span> <span class="token operator">=</span> <span class="token string">"spawn:started"</span><span class="token punctuation">,</span>\n  <span class="token constant">SPAWN_STDOUT</span> <span class="token operator">=</span> <span class="token string">"spawn:stdout"</span><span class="token punctuation">,</span>\n  <span class="token constant">SPAWN_STDERR</span> <span class="token operator">=</span> <span class="token string">"spawn:stderr"</span><span class="token punctuation">,</span>\n  <span class="token constant">SPAWN_FINISHED</span> <span class="token operator">=</span> <span class="token string">"spawn:finished"</span><span class="token punctuation">,</span>\n<span class="token punctuation">}</span>\n\n<span class="token comment">// Compatible with default command line encoding `cp936` on Windows platform</span>\n<span class="token keyword">const</span> iconvDecoding <span class="token operator">=</span> process<span class="token punctuation">.</span>platform <span class="token operator">===</span> <span class="token string">"win32"</span> <span class="token operator">?</span> <span class="token string">"cp936"</span> <span class="token operator">:</span> <span class="token string">"utf-8"</span><span class="token punctuation">;</span>\n\n<span class="token keyword">const</span> <span class="token function-variable function">runSpawn</span> <span class="token operator">=</span> <span class="token punctuation">(</span>cmd<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">,</span> args<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n  <span class="token keyword">const</span> process <span class="token operator">=</span> <span class="token function">spawn</span><span class="token punctuation">(</span>cmd<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>\n  browserWindow<span class="token punctuation">.</span>webContents<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>SpawnEvents<span class="token punctuation">.</span><span class="token constant">SPAWN_STARTED</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n\n  process<span class="token punctuation">.</span>stdout<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">"data"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>data<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n    browserWindow<span class="token punctuation">.</span>webContents<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>\n      SpawnEvents<span class="token punctuation">.</span><span class="token constant">SPAWN_STDOUT</span><span class="token punctuation">,</span>\n      iconv<span class="token punctuation">.</span><span class="token function">
1decode</span><span class="token punctuation">(</span>Buffer<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span> <span class="token string">"binary"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> iconvDecoding<span class="token punctuation">)</span><span class="token punctuation">,</span>\n    <span class="token punctuation">)</span><span class="token punctuation">;</span>\n  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n\n  process<span class="token punctuation">.</span>stderr<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">"data"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>data<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n    browserWindow<span class="token punctuation">.</span>webContents<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>\n      SpawnEvents<span class="token punctuation">.</span><span class="token constant">SPAWN_STDERR</span><span class="token punctuation">,</span>\n      iconv<span class="token punctuation">.</span><span class="token function">
1decode</span><span class="token punctuation">(</span>Buffer<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span> <span class="token string">"binary"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> iconvDecoding<span class="token punctuation">)</span><span class="token punctuation">,</span>\n    <span class="token punctuation">)</span><span class="token punctuation">;</span>\n  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n\n  process<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">"close"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>code<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n    browserWindow<span class="token punctuation">.</span>webContents<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>SpawnEvents<span class="token punctuation">.</span><span class="token constant">SPAWN_FINISHED</span><span class="token punctuation">,</span> code <span class="token operator">??</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre></div>'}}),"\n",p.createElement(s.p,null,"特别的,在 Windows 端,由于命令行工具默认采用 ",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">cp936</code>'}})," 编码,在输出中文时会出现乱码的现象。因此,在上面的实现中,笔者使用了 ",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">iconv-lite</code>'}})," 对标准输出、标准错误进行了重新解码。"),"\n"),"\n",p.createElement(s.li,null,"\n",p.createElement(s.p,null,"预加载器向渲染器暴露 ",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">ipcRenderer.on()</code>'}})," 方法。"),"\n",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="ts"><pre class="language-ts"><code class="language-ts"><span class="token comment">// main/preload.ts</span>\n<span class="token keyword">import</span> <span class="token punctuation">{</span> <span class="token keyword">type</span> <span class="token class-name">IpcRendererEvent</span> <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"electron"</span><span class="token punctuation">;</span>\n\n<span class="token keyword">const</span> ipc <span class="token operator">=</span> <span class="token punctuation">{</span>\n  <span class="token function-variable function">on</span><span class="token operator">:</span> <span class="token punctuation">(</span>channel<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">,</span> <span class="token function-variable function">func</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token operator">:</span> <span class="token builtin">unknown</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">void</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n    <span class="token keyword">const</span> <span class="token function-variable function">subscription</span> <span class="token operator">=</span> <span class="token punctuation">(</span>_event<span class="token operator">:</span> IpcRendererEvent<span class="token punctuation">,</span> <span class="token operator">...</span>args<span class="token operator">:</span> <span class="token builtin">unknown</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">=></span>
1\n      <span class="token function">func</span><span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span>\n    ipcRenderer<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>channel<span class="token punctuation">,</span> subscription<span class="token punctuation">)</span><span class="token punctuation">;</span>\n\n    <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n      ipcRenderer<span class="token punctuation">.</span><span class="token function">removeListener</span><span class="token punctuation">(</span>channel<span class="token punctuation">,</span> subscription<span class="token punctuation">)</span><span class="token punctuation">;</span>\n    <span class="token punctuation">}</span><span class="token punctuation">;</span>\n  <span class="token punctuation">}</span><span class="token punctuation">,</span>\n<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre></div>'}}),"\n",p.createElement(s.p,null,"其返回值是清除监听器的方法,可以配合 ",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">React.useEffect()</code>'}})," 使用。"),"\n"),"\n",p.createElement(s.li,null,"\n",p.createElement(s.p,null,"渲染器实现调用预加载器暴露的方法。"),"\n",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<div class="gatsby-highlight" data-language="tsx"><pre class="language-tsx"><code class="language-tsx"><span class="token comment">// renderer/path/to/component-listener.tsx</span>\n<span class="token keyword">import</span> <span class="token punctuation">{</span> useEffect<span class="token punctuation">,</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span>\n<span class="token keyword">import</span> <span class="token punctuation">{</span> SpawnEvents <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"path/to/main/background"</span><span class="token punctuation">;</span>\n\n<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n  <span class="token keyword">const</span> <span class="token punctuation">[</span>loading<span class="token punctuation">,</span> setLoading<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token generic-function"><span class="token function">useState</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token builtin">boolean</span><span class="token operator">></span></span></span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n  <span class="token keyword">const</span> <span class="token punctuation">[</span>stdout<span class="token punctuation">,</span> setStdout<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token generic-function"><span class="token function">useState</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token builtin">string</span><span class="token operator">></span></span></span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n  <span class="token keyword">const</span> <span class="token punctuation">[</span>stderr<span class="token punctuation">,</span> setStderr<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token generic-function"><span class="token function">useState</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token builtin">string</span><span class="token operator">></span></span></span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n\n  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n    <span class="token keyword">const</span> cleanupSpawnStarted <span class="token operator">=</span> window<span class="token punctuation">.</span>ipc<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>\n      SpawnEvents<span class="token punctuation">.</span><span class="token constant">SPAWN_STARTED</span><span class="token punctuation">,</span>
1\n      <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n        <span class="token function">setLoading</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n      <span class="token punctuation">}</span><span class="token punctuation">,</span>\n    <span class="token punctuation">)</span><span class="token punctuation">;</span>\n    <span class="token keyword">const</span> cleanupSpawnStdout <span class="token operator">=</span> window<span class="token punctuation">.</span>ipc<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>\n      SpawnEvents<span class="token punctuation">.</span><span class="token constant">SPAWN_STDOUT</span><span class="token punctuation">,</span>\n      <span class="token punctuation">(</span>data<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n        <span class="token function">setStdout</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>\n      <span class="token punctuation">}</span><span class="token punctuation">,</span>\n    <span class="token punctuation">)</span><span class="token punctuation">;</span>\n    <span class="token keyword">const</span> cleanupSpawnStderr <span class="token operator">=</span> window<span class="token punctuation">.</span>ipc<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>\n      SpawnEvents<span class="token punctuation">.</span><span class="token constant">SPAWN_STDERR</span><span class="token punctuation">,</span>\n      <span class="token punctuation">(</span>data<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n        <span class="token comment">// setStderr(data);</span>\n        <span class="token function">setStderr</span><span class="token punctuation">(</span><span class="token punctuation">(</span>prev<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n          <span class="token keyword">return</span> <span class="token punctuation">(</span>data <span class="token operator">+</span> <span class="token string">"\\n"</span> <span class="token operator">+</span> prev<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">substring</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">2000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n      <span class="token punctuation">}</span><span class="token punctuation">,</span>\n    <span class="token punctuation">)</span><span class="token punctuation">;</span>\n    <span class="token keyword">const</span> cleanupSpawnFinished <span class="token operator">=</span> window<span class="token punctuation">.</span>ipc<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span>\n      SpawnEvents<span class="token punctuation">.</span><span class="token constant">SPAWN_FINISHED</span><span class="token punctuation">,</span>\n      <span class="token punctuation">(</span>code<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
1\n        <span class="token function">setLoading</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n      <span class="token punctuation">}</span><span class="token punctuation">,</span>\n    <span class="token punctuation">)</span><span class="token punctuation">;</span>\n\n    <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>\n      <span class="token function">cleanupSpawnStarted</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n      <span class="token function">cleanupSpawnStdout</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n      <span class="token function">cleanupSpawnStderr</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n      <span class="token function">cleanupSpawnFinished</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n    <span class="token punctuation">}</span><span class="token punctuation">;</span>\n  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>\n\n  <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span></span><span class="token punctuation">></span></span><span class="token punctuation">{</span><span class="token comment">/* component details */</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span></span><span class="token punctuation">></span></span><span class="token punctuation">;</span>\n<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre></div>'}}),"\n",p.createElement(s.p,null,"一般来说,可执行文件会将日志信息重定向至 ",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">stderr</code>'}})," 标准错误,运行的最终结果重定向至 ",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">stdout</code>'}})," 标准输出。在本文中,我们需要展示的是 ",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">stderr</code>'}})," 的内容。"),"\n",p.createElement(s.p,null,"如果渲染器还需要对 ",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">stdout</code>'}})," 的结果进行下一步处理,同样可以在对应的组件中添加监听器:",p.createElement(s.span,{dangerouslySetInnerHTML:{__html:'<code class="language-text">window.ipc.on(SpawnEvents.SPAWN_STDOUT, (data: string) => {})</code>'}}),"。"),"\n"),"\n"),"\n",p.createElement(s.h3,null,"渲染器展示接收到的日志信息"),"\n",p.createElement(s.p,null,"现在,所有的链路都已经打通,查收编写代码努力的结晶吧!"),"\n",p.createElement(s.img,{src:"/static/44cdc55b11bdb279f47ae8319fbf6e93/real-time-execution-log.gif",alt:"实时展示日志信息"}))}var o=function(n){void 0===n&&(n={});const{wrapper:s}=Object.assign({},(0,t.R)(),n.components);return s?p.createElement(s,n,p.createElement(e,n)):e(n)},c=a(5643),l=a(9182),u=a.n(l),i=a(2838),k=a.n(i),r=a(4579),d=a.n(r),g=a(2030),m=a(7531),f=a(1099),E=a(4490),w=a(3625),y=a(5672),h=a(1579);u().extend(d()),u().extend(k());const S={a:n=>{let{href:s="",children:a}=n;const t=!(null!=s&&s.startsWith("#")),e=t?s:`#${encodeURIComponent(s.slice(1))}`;return p.createElement("a",{href:e,target:t?"_blank":void 0,rel:"noreferrer"},a)},img:n=>{const{alt:s="The author is too lazy to give an alt",src:a,...t}=n;return p.createElement("a",{href:a,"data-fancybox":"gallery","data-caption":s},p.createElement("img",Object.assign({src:a,alt:s},t)))},Card:m.A,Link:g.Link,HintText:f.A},b=n=>{var s;let{children:a,data:e}=n;const{mdx:{fields:{isDraft:o},frontmatter:{title:l,date:i,updated:k,categories:r,tags:d,timeliness:m}}}=e,f=p.useRef(null),E=u().utc(i).tz("Asia/Shanghai"),b=k?u().utc(k).tz("Asia/Shanghai"):E,[v,_]=p.useState(null),x=null!==v?v.diff(b,"days"):null,T="number"==typeof m?m:365,I=null!==x&&T>=0&&x>=T;return p.useEffect(()=>{p.startTransition(()=>_(u()().tz("Asia/Shanghai")))},[]),p.useEffect(()=>{var n;const s=null===(n=f.current)||void 0===n?void 0:n.querySelectorAll("a.gatsby-resp-image-link");
1return null==s||s.forEach(n=>{const s=n.children.item(1);n.setAttribute("data-fancybox","gallery"),n.setAttribute("data-caption",s.alt)}),c.lX.bind("[data-fancybox]",{on:{initLayout:n=>{var s,a;null===(s=n.getContainer())||void 0===s||s.setAttribute("theme",null!==(a=document.documentElement.dataset.theme)&&void 0!==a?a:"light")}}}),()=>c.lX.unbind("[data-fancybox]")},[]),(0,h.A)(f),p.createElement("div",{className:"mx-auto flex max-w-xl flex-col gap-y-12"},p.createElement("div",{className:"flex flex-col gap-4"},(null==r?void 0:r.length)&&p.createElement(g.Link,{to:`/categories/${encodeURIComponent(r[0])}`,className:"w-fit rounded bg-background-lighter px-3 py-2 leading-normal transition-opacity hover:opacity-75"},p.createElement("span",{className:`cursor-pointer bg-gradient-to-tr from-0% via-40% to-90% bg-clip-text text-lg font-bold leading-none text-transparent ${null!==(s=y.Y[r[0]])&&void 0!==s?s:""}`},r[0])),p.createElement("h1",{className:"text-3xl font-bold"},l),p.createElement("div",{className:"item-secondary flex flex-col gap-2 lg:flex-row"},i&&p.createElement("span",{title:`首次发布于:${E.format("YYYY-MM-DD HH:mm:ss [UTC+8]")}\n最后更新于:${b.format("YYYY-MM-DD HH:mm:ss [UTC+8]")}`},E.format("MM 月 DD 日 YYYY 年")),(null==d?void 0:d.length)&&p.createElement("div",{className:"flex flex-1 flex-wrap gap-2 lg:before:content-['•']"},d.map(n=>p.createElement(w.A,{key:n,name:n,className:"item-secondary item-selectable"}))))),p.createElement("article",{ref:f,className:"heti post-entry"},o&&p.createElement("blockquote",{className:"!border-red-400"},"这是一篇",p.createElement("strong",null,"尚未正式发布"),"的博客,内容可能暂不完善或存在纰漏,建议您仔细评估文章的可靠性。"),I&&null!==x&&p.createElement("blockquote",{className:"!border-orange-400"},"这是一篇",p.createElement("strong",null,"最后更新于 ",x," 天前"),"的博客,内容可能随着时间的推移而变得不再适用,建议您仔细评估文章的有效性。"),p.createElement(t.x,{components:S},a)))},v=n=>{let{data:s}=n;return p.createElement(E.A,{title:String(s.mdx.frontmatter.title)})};function _(n){return p.createElement(b,n,p.createElement(o,n))}}}]);
2//# sourceMappingURL=component---src-templates-post-tsx-content-file-path-blog-posts-electron-real-time-print-execution-log-mdx-2661816b933944e0c926.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.