Electron ServiceWorkers API:在主进程掌握 Service Worker 的运行状态、日志与通信
2026/9/7 2:35:37 网站建设 项目流程

Electron ServiceWorkers API:在主进程掌握 Service Worker 的运行状态、日志与通信

【免费下载链接】electron:electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS项目地址: https://gitcode.com/GitHub_Trending/el/electron

session.serviceWorkers是 Electron 提供给主进程(Main Process)的 API,用于查询某个会话中所有正在运行的 Service Worker、监听其控制台日志与注册/生命周期事件,并通过ServiceWorkerMain实例与 Worker 进程直接进行 IPC 通信。读完本文,你将能够完整掌握ServiceWorkers类的全部事件与方法、理解其在 源码 中如何挂接 Chromium 的content::ServiceWorkerContext观察者,并学会在应用启动时为已注册的 Worker 主动启动并下发消息。

一、定位与获取方式:SessionserviceWorkers属性

ServiceWorkers类不直接从'electron'模块导出,它只能作为其他 API 方法的返回值获得。获取它的唯一入口是Session实例的serviceWorkers属性:

const { session } = require('electron') // 获取所有正在运行的 service worker console.log(session.defaultSession.serviceWorkers.getAllRunning()) // 监听控制台日志,并获取发送日志的 worker 信息 session.defaultSession.serviceWorkers.on('console-message', (event, messageDetails) => { console.log( 'Got service worker message', messageDetails, 'from', session.defaultSession.serviceWorkers.getFromVersionID(messageDetails.versionId) ) })

从源码可以确认这一绑定关系:Session的 JS 绑定在 electron_api_session.cc 中通过.SetProperty("serviceWorkers", &Session::ServiceWorkerContext)注册,其实现会懒创建并缓存一个ServiceWorkerContext对象。值得注意的是,ServiceWorkerContext构造时还会把会话对应的存储分区配置登记进BrowsingDataRemover的数据类型列表(DATA_TYPE_SERVICE_WORKERS),因此session.clearStorageData()同样能清理已注册的 Service Worker——这一点在 测试用例 中被明确使用:每次用例前后都调用ses.clearStorageData()以保证隔离。

ServiceWorkerContext与底层的关系也很直接:其构造函数从ElectronBrowserContext的默认存储分区取出content::ServiceWorkerContext,并调用AddObserver(this)注册自己,析构时移除观察者。这意味着ServiceWorkers的全部事件与方法,本质都是对 Chromium 内容层 Service Worker 基础设施的封装。

二、ServiceWorkerInfo:每个 Worker 版本的描述对象

ServiceWorkers的多个方法都会返回ServiceWorkerInfo对象(结构定义见 service-worker-info.md):

字段类型说明
scriptUrlstring该 Service Worker 运行的脚本的完整 URL
scopestring该 Service Worker 生效的基准 URL
renderProcessIdnumber该 Worker 所在进程的虚拟 ID(非操作系统 PID),与webContents.getProcessId()使用同一套 ID 体系
versionIdnumber该 Service Worker 版本的 ID

在实现层,scriptUrlscoperenderProcessIdServiceWorkerRunningInfoToDictcontent::ServiceWorkerRunningInfo直接组装(见 electron_api_service_worker_context.cc#L68-L76)。

三、实例事件

Event:console-message

当某个 Service Worker 向控制台输出内容时发出,回调参数为:

  • eventEvent
  • messageDetailsObject
    • messagestring - 实际的控制台消息文本
    • versionIdnumber - 发送日志的 Service Worker 的版本 ID
    • sourcestring - 消息来源类型,可能为javascriptxmlnetworkconsole-apistoragerenderingsecuritydeprecationworkerviolationinterventionrecommendationother
    • levelnumber - 日志级别,0~3,依次对应verboseinfowarningerror
    • sourceUrlstring - 消息来源的 URL
    • lineNumbernumber - 触发该消息的源码行号

source字段的字符串映射在 MessageSourceToString 中逐一对应 Blink 的ConsoleMessageSource枚举;level则是直接把message.message_level转成int32_t后透出。spec/api-service-workers-spec.ts#L77-L96 验证了级别映射:console.log/info为 1,warn为 2,error为 3,且来源均为console-api

Event:registration-completed

当 Service Worker 注册成功时发出,可能发生在navigator.serviceWorker.register('/sw.js')成功 resolve 之后,也可能发生在 Chrome 扩展加载时。回调参数:

  • eventEvent
  • detailsObject
    • scopestring - 该 Service Worker 注册的基准 URL

Event:running-status-changedExperimental

当某个 Service Worker 的运行状态变化时发出。回调参数:

  • details
    • versionIdnumber - 状态发生变化的 Service Worker 版本 ID
    • runningStatusstring - 运行状态,可能为startingrunningstoppingstopped

从源码结构看,这个事件是四个 Chromium 生命周期回调的统一出口:OnVersionStartingRunning/OnVersionStartedRunning/OnVersionStoppingRunning/OnVersionStoppedRunning分别转调OnRunningStatusChanged,后者先通知对应ServiceWorkerMain实例,再向 JS 侧发射事件(见 electron_api_service_worker_context.cc#L99-L162)。

四、实例方法

serviceWorkers.getAllRunning()

返回Record<number, ServiceWorkerInfo>—— 键为 Service Worker 版本 ID、值为对应信息的对象。底层直接遍历content::ServiceWorkerContext::GetRunningServiceWorkerInfos()返回的flat_map,逐个版本组装字典(GetAllRunningWorkerInfo)。没有任何 Worker 运行时返回空对象{},这一点在 spec/api-service-workers-spec.ts#L52-L54 中得到验证。

serviceWorkers.getInfoFromVersionID(versionId)

  • versionIdnumber - Service Worker 版本 ID

返回ServiceWorkerInfo。若该 Worker 不存在或未运行,方法会抛出异常(源码中抛出"Could not find service worker with that version_id")。

serviceWorkers.getFromVersionID(versionId)Deprecated

  • versionIdnumber - Service Worker 版本 ID

返回ServiceWorkerInfo。若该 Worker 不存在或未运行则抛出异常。

已弃用:请改用getInfoFromVersionID。源码中GetFromVersionID会先发出弃用警告(ServiceWorkersDeprecateGetFromVersionID),然后委托给GetInfoFromVersionID(见 electron_api_service_worker_context.cc#L198-L208)。

serviceWorkers.getWorkerFromVersionID(versionId)Experimental

  • versionIdnumber - Service Worker 版本 ID

返回ServiceWorkerMain | undefined—— 与该版本 ID 关联的 Service Worker 实例;若没有对应版本,或其运行状态已变为stopped,则返回undefined

serviceWorkers.startWorkerForScope(scope)Experimental

  • scopestring - 要启动的 Service Worker 的 scope

返回Promise<ServiceWorkerMain>—— Worker 启动后 resolve。若该 scope 的 Worker 已在运行,则不做任何额外操作。底层调用content::ServiceWorkerContext::StartWorkerForScope,以 scope 的一方 origin 构造StorageKey并异步等待结果(StartWorkerForScope)。

典型实战场景:应用启动时为所有已注册的 Worker 兜底启动,并通过 IPC 通知其"有窗口已创建":

const { app, session } = require('electron') const { serviceWorkers } = session.defaultSession // 收集所有 service worker 的 scope const workerScopes = Object.values(serviceWorkers.getAllRunning()).map((info) => info.scope) app.on('browser-window-created', async (event, window) => { for (const scope of workerScopes) { try { // 确保 worker 已启动 const serviceWorker = await serviceWorkers.startWorkerForScope(scope) serviceWorker.send('window-created', { windowId: window.id }) } catch (error) { console.error(`Failed to start service worker for ${scope}`) console.error(error) } } })

五、ServiceWorkerMain:与 Worker 进程通信的句柄

startWorkerForScopegetWorkerFromVersionID返回的ServiceWorkerMain实例代表某个 scope 下脚本的某个具体版本(详见 service-worker-main.md),其成员同样为Experimental

  • 只读属性
    • scope:Worker 的 scope URL
    • scriptURL:Worker 脚本 URL
    • versionId:该 scope 下脚本版本的 ID
    • ipc:一个作用域限定到该 Worker 的IpcMainServiceWorker实例
  • 方法
    • isDestroyed():Worker 版本是否已被销毁
    • send(channel, ...args):通过channel向 Worker 进程发送异步消息,参数按结构化克隆算法序列化(与postMessage相同),发送 Function、Promise、Symbol、WeakMap 或 WeakSet 会抛异常;Worker 侧可用ipcRenderer监听同一channel接收
    • startTask():发起一个任务以在end()被调用前保持 Worker 存活,返回对象仅含end方法;若从不调用end,Worker 在空闲时也不会终止

ServiceWorkerMain的 C++ 实现(electron_api_service_worker_main.h)透露了几个关键设计:

  • 实例由browser_context_id + storage_partition_config + version_id三元组(ServiceWorkerKey)唯一标识,保证不同会话/分区中相同 versionId 的 Worker 不会混淆;
  • 对象在 cppgc 堆上通过SelfKeepAlive自持有,生命周期与底层 Service Worker 版本对齐,使得已注册的 IPC 处理器在整个存活期内都能正常分发;
  • 通过 Mojo 关联远程对象(mojom::ElectronRenderer)与渲染进程建立连接来完成send通信,并在状态变化时可能断开该连接。

Worker 侧的回复通道由IpcMainServiceWorker提供(详见 ipc-main-service-worker.md):它是IpcMain的变体,提供ononceremoveListenerremoveAllListenershandlehandleOnceremoveHandler等方法,专用于主进程与 Service Worker 之间的send/invoke双向通信。相关端到端行为在 spec/api-service-worker-main-spec.ts 中有独立测试覆盖。

六、内部实现与内部方法一览

ServiceWorkerContext在 GetObjectTemplateBuilder 中除了注册文档列出的公开方法外,还暴露了两个以下划线开头的内部方法(未在公开文档中列出,属于实现细节):

  • _getWorkerFromVersionIDIfExists(versionId):按ServiceWorkerKey查找已存在的ServiceWorkerMain,找不到时不抛异常;
  • _stopAllWorkers():调用底层StopAllServiceWorkers停止该会话的所有 Worker,返回 Promise。

事件与状态同步的完整链路可以概括为:

  1. content::ServiceWorkerContext观察者回调(注册完成 / 控制台消息 / 状态变化 / 版本冗余)触发ServiceWorkerContext对应方法;
  2. 控制台消息经OnReportConsoleMessage组装为versionIdsourcelevelmessagelineNumbersourceUrl后发出console-message事件;
  3. 状态变化经OnRunningStatusChanged更新ServiceWorkerMain后发出running-status-changed事件;
  4. 方法调用(getAllRunninggetInfoFromVersionID等)直接读取GetRunningServiceWorkerInfos()的内存快照。

七、测试验证与使用前提

  • spec/api-service-workers-spec.ts:覆盖getAllRunning()(初始为空、加载注册页后恰好一个)、getFromVersionID()scriptUrl/scope正确性、console-message的 source 与 level 映射;
  • spec/api-service-worker-main-spec.ts:覆盖ServiceWorkerMain的实验性能力;
  • 事件触发的前提是页面真实注册了 Service Worker(如navigator.serviceWorker.register('/sw.js')),且监听方需持有正确的Session实例——不同 partition 的会话各自独立。

适用前提小结

  • running-status-changedgetWorkerFromVersionIDstartWorkerForScope及全部ServiceWorkerMain能力均为Experimental,接口可能随版本演进调整;
  • getFromVersionID已弃用,新代码应使用getInfoFromVersionID
  • getInfoFromVersionIDgetFromVersionID在目标 Worker 不存在或未运行时会抛异常,生产代码中建议配合getAllRunning()的结果或try/catch做防御;
  • 与 Worker 通信走结构化克隆,函数等不可克隆值不能通过send传递。

【免费下载链接】electron:electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS项目地址: https://gitcode.com/GitHub_Trending/el/electron

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询