ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Chrome Apps 的 onRestarted 事件实战:restarted-demo 教你如何在浏览器重启后恢复应用状态

Chrome Apps 的 onRestarted 事件实战:restarted-demo 教你如何在浏览器重启后恢复应用状态 Chrome Apps 的 onRestarted 事件实战restarted-demo 教你如何在浏览器重启后恢复应用状态【免费下载链接】chrome-extensions-samplesChrome Extensions Samples项目地址: https://gitcode.com/gh_mirrors/ch/chrome-extensions-samples本指南以 chrome-extensions-samples 仓库中_archive/apps/samples/restarted-demo示例为蓝本深入讲解 Chrome 打包应用Packaged App中chrome.app.runtime.onRestarted事件的作用机制当应用因浏览器意外终止如崩溃、重启而被系统恢复时如何借助chrome.storage.local持久化数据把界面状态完整还原到崩溃前的样子。读完本文你将掌握「启动即恢复」状态机的基本设计思路、onLaunched与onRestarted的职责划分以及一份可直接运行的计数器恢复应用完整源码。onRestarted 事件为“意外终止后的恢复”而生Chrome 打包应用的生命周期由chrome.app.runtime提供的事件驱动。普通启动走onLaunched而本示例聚焦的是另一个容易被忽略的事件 ——onRestarted当应用在被意外终止之后被恢复时例如浏览器重启系统会向应用发送一个onRestarted事件应用应当借此把自身恢复到上次运行时的状态。「意外终止」与「正常关闭」的关键区别在于正常关闭时应用有机会自行清理窗口与数据而崩溃或浏览器整体重启时应用进程被直接销毁所有内存状态包括内存中的对象、未落盘的计数都会丢失。onRestarted正是系统提供给应用的后悔药入口让开发者有机会把持久化在磁盘上的数据重新加载回来。该事件属于chrome.app.runtimeAPImanifest 中对应app: {background: ...}声明的应用后台页与chrome.storage、chrome.app.window一起构成了本示例的三大 API 支柱。示例概览与最小 manifestrestarted-demo实现了一个简单却完整的语义闭环应用在启动时创建一个新计数器而在应用重启时恢复所有已存在的计数器。整个示例只包含四个文件_archive/apps/samples/restarted-demo/background.js全部业务逻辑计数器模型 事件监听_archive/apps/samples/restarted-demo/main.html应用窗口界面_archive/apps/samples/restarted-demo/manifest.json应用清单_archive/apps/samples/restarted-demo/sample_support_metadata.json示例元数据其 manifest.json 完整内容如下注意这是 Manifest V2 时代打包应用的经典结构{ name: Restarted Event Sample, version: 2, manifest_version: 2, app: { background: { scripts: [ background.js ] } }, permissions: [ storage ] }两个值得注意的点权限只需要一个storage用于访问chrome.storage.localchrome.app.runtime与chrome.app.window属于打包应用内建 API无需额外权限声明后台脚本通过app: {background: {scripts: [...]}}声明这正是onLaunched/onRestarted等应用级事件得以注册的载体。状态持久化的核心Counter 模型与防抖式写入恢复状态的前提是有状态可恢复因此示例把计数器抽象成了一个带持久化能力的Counter对象。构造函数如下function Counter(id, clicks, startedBy) { this.id id; this.clicks clicks; this.startedBy startedBy; this.saving false; this.listeners []; this.save(); Counter.all.push(this); }每个计数器有四个关键属性id存储键、clicks当前点击数、startedBy标记来源是launched还是restarted、saving写入中的防重入标志同时维护一个listeners订阅者列表用于界面刷新。防抖与合并写入的save()save()是持久化的核心实现了一个轻量的写入中防重入 快照对比重存机制Counter.prototype.save function() { if (this.saving) return; this.saving true; var self this; (function(clicks) { var counters {}; counters[self.id] {clicks: clicks}; var data {counters: counters}; chrome.storage.local.get(counters, function(data) { if (!data.counters) { data.counters {}; } data.counters[self.id] {clicks: clicks}; chrome.storage.local.set(data, function() { self.saving false; if (self.clicks ! clicks) { // self.clicks changed while we were saving, so save again. self.save(); } }); }); })(this.clicks); };这段代码解决了chrome.storage.local异步写模型下的两个典型问题写入合并saving标志保证同一时刻只有一个写入在途用户连续快速点击不会触发 N 次串行写入快照对比重存闭包捕获写入发起时的clicks快照写入完成后若发现this.clicks已经变化写入期间又发生了点击则递归再调一次save()补存最新值确保落盘数据最终一致。关闭时的清理与界面联动当窗口被关闭时close()会从chrome.storage.local中删除该计数器的记录并把自身从全局列表移除避免已关闭窗口的计数器在下次重启时被错误恢复Counter.prototype.close function() { this.clearListeners(); var self this; chrome.storage.local.get(counters, function(data) { delete data.counters[self.id]; chrome.storage.local.set(data); }); // Remove self from global list. var i Counter.all.indexOf(this); if (i ! -1) Counter.splice(i, 1); };界面联动则由attachToWindow()完成把窗口的onClosed绑定到close()把计数变化通过监听器同步到页面上started-by与number两个元素并给clickButton绑定increment()、给logLocalStorage绑定存储查看函数。main.html中对应的正是Started by、Clicks两个表格字段与Click、Log local storage两个按钮。onLaunched 与 onRestarted两条启动路径的分工示例的精华在于用两个事件把新会话与恢复会话彻底分离onLaunched从零开始chrome.app.runtime.onLaunched.addListener(function() { if (Counter.all.length 0) { // We might have left over state from a previous hard shutdown. chrome.storage.local.clear(); } chrome.storage.local.get(nextId, function(data) { if (!data.nextId) data.nextId 0; var id data.nextId; var counter new Counter(id, 0, launched); runApp(counter); chrome.storage.local.set(data); }); });这里有一个值得仔细品味的细节当Counter.all为空时说明当前内存中没有任何活跃计数器会先执行chrome.storage.local.clear()清掉历史残留。注释点明了意图——我们可能残留了上次硬关机留下的状态。配合nextId自增序号每次普通启动都会创建一个startedBy launched、点击数为 0 的新计数器。onRestarted还原现场chrome.app.runtime.onRestarted.addListener(function() { chrome.storage.local.get(null, function(data) { for (var id in data.counters) { var clicks data.counters[id].clicks; var counter new Counter(id, clicks, restarted); runApp(counter); } }); });两条路径的对比一目了然维度onLaunchedonRestarted触发时机用户显式启动应用意外终止后被系统恢复数据来源新建clicks 0从chrome.storage.local读回startedBylaunchedrestarted是否清理残留无活跃计数器时清空不动数据逐条恢复存储键自增nextId复用原id注意onRestarted中chrome.storage.local.get(null, ...)会取出整个存储对象随后遍历data.counters为每个持久化过的计数器按原id、原clicks重建Counter实例——这正是恢复到上次运行时的状态的落地实现。界面上 main.html 的第一行说明文字 This app starts with a click count of zero when launched, but preserves that count when restarted. 也精确概括了这一行为。窗口恢复runApp 与窗口 id 复用计数器重建之后还需要把窗口开回来。runApp()负责创建应用窗口function runApp(counter) { chrome.app.window.create(main.html, { id: counter.id , innerBounds: { width: 800, height: 600 } }, function(win) { win.contentWindow.onload function() { counter.attachToWindow(win, win.contentWindow.document); }; }); }关键点是id选项Chrome Apps 的chrome.app.window.create支持为窗口指定持久化 id同名 id 的窗口在被恢复时会保留上次的位置与尺寸状态。这里直接把计数器的id作为窗口 id既让每个计数器拥有独立窗口也保证了重启恢复的窗口能尽量还原原布局。窗口创建完成后通过contentWindow.onload把计数器挂载到窗口文档上完成数据与界面的最终绑定。验证流程如何在真实浏览器中观察恢复行为要亲身体验onRestarted可按以下步骤验证需 Chrome 及打包应用支持环境进入_archive/apps/samples/restarted-demo目录在chrome://extensions开启开发者模式通过加载已解压的扩展程序载入该目录启动应用多次点击Click按钮将计数增加到任意值如 5此时数据已写入chrome.storage.local点击Log local storage按钮可在控制台看到类似local storage: {nextId: 1, counters: {0: {clicks: 5}}}的输出确认持久化内容通过浏览器重启或应用右键菜单中的 Simulate Browser Restart模拟浏览器重启强制触发恢复流程重启后应用自动以Started by restarted标识重新出现且Clicks恢复为 5 —— 而非从 0 开始。上图中的界面正展示了该验证场景标题栏显示 Restarted demo字段值为 Started by restarted、Clicks为 5右键菜单中 Simulate Browser Restart 高亮可见。示例的 sample_support_metadata.json 还记录了该示例的跨平台验证信息ios: {works: true, comments: Restart must be done via Safari remote debugging.}即 iOS 环境下应用可正常工作但重启触发需通过 Safari 远程调试完成。实现要点回顾与适用前提回顾整个示例可以提炼出四条可复用的设计经验状态必须主动落盘所有需要跨崩溃保留的数据点击数、id都通过chrome.storage.local持久化内存对象不承担任何恢复责任事件分工明确onLaunched处理全新会话onRestarted只做读回 重建两者互不干扰写入要考虑异步竞态save()中的saving标志与快照对比重存是应对chrome.storage.local异步回调的实用范式窗口 id 用于布局恢复chrome.app.window.create的id参数让恢复的窗口尽量还原原位置尺寸。需要说明的是本示例位于仓库的_archive/apps归档目录下属于 Chrome 打包应用Chrome Apps时代的示例chrome.app.runtime、chrome.app.window等 API 现已不再演进但它所展示的事件驱动恢复 本地持久化 防抖写入模式对于理解现代扩展中chrome.storage的持久化用法、Service Worker 生命周期下的状态恢复设计仍然具有直接的借鉴价值。如果你在浏览器重启后需要恢复扩展自身状态完全可以参照onRestarted的这套读回数据 → 重建对象 → 重建界面的流程来组织自己的代码。延伸阅读示例 README官方对onRestarted事件与示例行为的说明_archive/apps/samples/restarted-demo/background.js本文全部核心代码_archive/apps/samples/restarted-demo/main.html应用界面_archive/apps/samples/restarted-demo/manifest.json应用清单仓库中 _archive/apps/samples/storage 与 _archive/apps/samples/window-state 等示例可进一步了解chrome.storage与窗口状态的更多用法【免费下载链接】chrome-extensions-samplesChrome Extensions Samples项目地址: https://gitcode.com/gh_mirrors/ch/chrome-extensions-samples创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表