鸿蒙 PC Markdown 编辑器十兆级大文档保护模式
鸿蒙 PC Markdown 编辑器十兆级大文档保护模式仓库地址https://gitcode.com/VON-/codex_md_oh代码基线大文档实现位于当前 Web 编辑器主线精确十兆级回归提交为941a1dc状态同步提交为6c9d88f。大文档能力首先是降级设计桌面 Markdown 编辑器常把“能打开大文件”写成性能卖点但真正困难的不是把字符串读进内存而是在语法解析、自动换行、撤销历史、实时预览、公式、图表、图片、字数统计、恢复快照和原生桥接同时存在时仍保持可编辑。十兆级正文进入完整渲染链后实际内存可能是源文件的数倍甚至数十倍。OhMarkdown 没有用无限功能换取一张成功截图而是给大文档建立保护模式源码编辑与保存优先保留语法扩展、自动换行、预览、专业渲染、导出、链接助手和周期恢复快照暂停。用户仍然能读取、修改并保存最重要的文本事实产品则避免在已经超过资源预算时继续制造 DOM、SVG 和位图。这是一种 PC 工具应有的失败策略。正常规模下提供丰富体验越过明确阈值后主动收缩状态栏给出可识别状态所有入口遵守同一约束。比起某个按钮点击后长时间无响应这种可预测降级更值得长期信任。十兆字节与十兆字符不能混写当前 Playwright 用例构造的是10 * 1024 * 1024个 JavaScript UTF-16 代码单元严格说它验证十兆级编辑器文档长度不等价于“文件恰好 10 MiB”。中文字符写成 UTF-8 时通常占三个字节换行与 ASCII 又占一个字节因此同一字符串落盘后的字节数会大于 10 MiB。consttargetLength10*1024*1024;constline鸿蒙PC大文档\n;constcontentline.repeat(Math.ceil(targetLength/line.length)).slice(0,targetLength);这一区分直接影响工程结论。Web 编辑器按content.length决定 CodeMirror 配置所以代码单元是正确的 Web 边界Core File Kit 的读取预算、磁盘吞吐和保存完整性则应该按 UTF-8 字节测量。文章把两类指标分开避免把浏览器回归的 87 ms 写成完整 10 MiB 文件打开时间。后续真机基准应同时记录文件字节数、解码后代码单元数、Unicode 组成、行数、最长行、换行格式和图片引用数量。只有这样英文日志、中文长文和单行压缩文本的结果才可比较。阈值必须在 EditorState 创建前判断大文件保护若在编辑器初始化完成后才打开就已经太晚。CodeMirror 可能先加载 Markdown 语言扩展、构建语法状态、测量超长行并创建换行布局然后应用才发现正文超过阈值。峰值成本已经支付切回源码模式无法撤销初始化时的卡顿。OhMarkdown 在createEditorState入口根据正文长度选扩展集合。超过五兆代码单元时使用minimalSetup不加载 Markdown 语言扩展和lineWrapping小文档仍使用basicSetup与完整 Markdown 编辑体验。constLARGE_DOCUMENT_CHARACTER_THRESHOLD5*1024*1024;functioncreateEditorState(content:string):EditorState{constuseLargeDocumentSetupcontent.lengthLARGE_DOCUMENT_CHARACTER_THRESHOLD;constlineSeparatorcontent.includes(\r\n)?\r\n:\n;returnEditorState.create({doc:content,extensions:[useLargeDocumentSetup?minimalSetup:basicSetup,useLargeDocumentSetup?[]:markdown({base:markdownLanguage}),EditorState.lineSeparator.of(lineSeparator),localeCompartment.of(placeholder(getEditorMessages().editorPlaceholder)),useLargeDocumentSetup?[]:EditorView.lineWrapping]});}阈值名称使用CHARACTER而不是BYTE与实现事实保持一致。这个细节能阻止未来维护者误把文件大小直接传入或者以为中文内容与英文内容有相同的字节边界。为什么阈值是五兆而测试是十兆五兆是保护模式触发点十兆是阶段验收样本。只在阈值附近测试可以证明条件表达式工作却不能证明进入保护模式后还能承载更高一级规模。十兆样本相当于给降级路径留出一倍距离能发现setDocument、getDocument、桥接状态和模式切换中仍然存在的全文复制。这不意味着支持上限就是十兆。当前产品没有把十兆写成硬拒绝线也没有证明一百兆仍安全。一个严谨的能力声明应写成十兆级样本在当前 Web 回归中能于三秒预算内进入保护模式并保持源码区可见更大规模、真机内存和持续编辑仍需专项数据。阈值未来若调整必须同时评估功能体验和风险。过低会让普通长文过早失去预览过高则会在内存不足设备上触发冻结。合理做法是在固定真机矩阵上采集峰值内存、输入延迟和首次可交互时间再通过配置或设备能力档位演进。模式请求必须被保护状态拒绝大文档加载完成后外部工具栏、快捷键、右键菜单或恢复的旧会话都可能请求split或preview。仅在加载时设置 source 不够所有后续模式入口都必须检查保护状态。functionupdateLargeDocumentMode(documentLength:number):void{largeDocumentModedocumentLengthLARGE_DOCUMENT_CHARACTER_THRESHOLD;if(largeDocumentModecurrentMode!source){currentModesource;workspace.dataset.modesource;}}functionsetMode(mode:ViewMode):void{if(largeDocumentModemode!source)return;currentModemode;workspace.dataset.modemode;}命令面板还会把预览、分栏、HTML、PNG 和打印标记为不可用编辑器右键中的插入链接也遵守同一状态。入口层禁用负责用户反馈执行层再校验负责安全两层同时存在才能防止原生桥接或未来快捷键绕过界面禁用。字数统计为什么返回负一普通文档每次变更都会计算字数并通知原生状态栏。对十兆级正文执行全量词数扫描会把每次输入都变成 O(n) 工作还可能产生临时字符串。大文档模式将wordCount设为-1由原生界面显示保护状态而不是一个看似精确但持续拖慢输入的数字。functionflushToNative(content?:string):void{window.clearTimeout(bridgeTimer);if(pendingNativeChange){constwordCountlargeDocumentMode?-1:countWords(content??editor.state.sliceDoc());window.ohMarkdownBridge?.onChange(wordCount,pendingDirty);pendingNativeChangefalse;}}负一是跨 ArkWeb 与 ArkUI 的协议值不应直接展示给用户。协议需要集中解释否则状态栏可能出现“-1 字”。未来若要提供大文件统计可以改为后台分块计算和“约 N 字”但不能重新把同步全量扫描放回每次输入路径。恢复快照为什么暂停周期恢复通常是编辑器的优势但对十兆级正文每 1.5 秒把全文从 CodeMirror 切出、跨桥传给 ArkTS、序列化并原子写盘会持续制造内存和存储压力。保护模式暂停周期快照避免安全功能本身成为卡顿或崩溃原因。functionscheduleRecoverySnapshot():void{if(!pendingDirty||largeDocumentMode){window.clearTimeout(recoveryTimer);recoveryTimerundefined;return;}if(recoveryTimer!undefined)return;recoveryTimerwindow.setTimeout(flushRecoverySnapshot,RECOVERY_SNAPSHOT_INTERVAL_MILLISECONDS);}暂停快照并不代表可以忽略数据安全。大文档仍需清楚提示保护状态保存命令必须可用关闭窗口仍要走未保存确认。未来可以设计增量日志或基于 CodeMirror transaction 的恢复格式但在没有证明增量方案可靠之前宁可明确限制不使用高频全文副本冒充安全。延迟桥接减少跨进程复制正文超过一兆后Web 到原生的变更通知防抖从 160 ms 延长到 600 ms。通知本身不总是传全文但保存、冲突与会话同步可能触发内容读取。更长防抖减少连续输入中重复的边界穿越让编辑器先处理用户输入再合并状态更新。这不是把延迟藏起来。状态栏和保存状态允许数百毫秒最终一致光标与文本回显则必须即时。把不同交互按响应要求分层是 PC 编辑器性能设计的重要方法输入路径最优先统计和预览可以稍后磁盘持久化按明确策略完成。自动化用例验证了什么新增 Playwright 用例在页面内部精确构造十兆级字符串记录setDocument与请求预览的合计时间随后验证三个事实取回的文档长度完全一致模式仍为 source耗时小于三秒。界面层还断言编辑器可见、预览隐藏。test(十兆字节文档在三秒内进入保护模式并保持源码可读,async({page}){constresultawaitpage.evaluate((){consthostwindowasunknownasEditorTestWindow;consttargetLength10*1024*1024;constline鸿蒙PC大文档\n;constcontentline.repeat(Math.ceil(targetLength/line.length)).slice(0,targetLength);conststartedAtperformance.now();host.OhMarkdownEditor.setDocument(content);host.OhMarkdownEditor.setMode(preview);return{elapsedMilliseconds:performance.now()-startedAt,documentLength:host.OhMarkdownEditor.getDocument().length,mode:document.querySelector(#workspace)?.getAttribute(data-mode)};});expect(result.documentLength).toBe(10*1024*1024);expect(result.mode).toBe(source);expect(result.elapsedMilliseconds).toBeLessThan(3000);});当前 Chromium 回归记录 87 msPlaywright 全量为44/44。三秒是退化门禁不是把本机 87 ms 变成所有设备的承诺。自动化能稳定发现模式绕过和数量级退化但不能覆盖 Core File Kit 读取、ArkTS/ArkWeb 首次装载、真机调度和磁盘温度。第一次失败暴露了语料错误用例初版按人工估计的中文行长度计算重复次数最终只有 9,320,680 个代码单元长度断言失败。修复后改用line.length作为生成公式的事实来源再通过slice精确截断。这个失败说明性能测试也需要先验证样本。文件名叫10mb.md、循环写了一百万次、日志打印“十兆”都不能证明语料正确。测试应在计时之外断言长度和字节数否则会出现样本逐渐缩小、成绩却越来越好的假优化。对中文语料尤其如此JavaScript 长度、Unicode 码点、UTF-8 字节和用户看到的字形不是同一单位。工程报告必须注明测量单位不能把数字便利放在事实之前。应用内部的大文件状态下图来自 OhMarkdown 应用内部的大文件保护界面。源码区保持可用预览能力退出状态栏以大文件状态替代昂贵的实时字数统计。图片用于证明产品确实有可见的保护状态和源码工作区不用于证明 87 ms 或十兆级长度。性能数字来自自动化日志视觉状态来自应用截图文件整链结果来自模拟器或真机测试。把三类证据分开可以避免一张界面图承担它不能证明的性能结论。为什么预览和导出要一起关闭Markdown 预览不是一次简单字符串替换。专业渲染包含 MarkdownIt、DOMPurify、KaTeX、Mermaid、代码高亮、本地图片读取和 Blob 生命周期。HTML 导出还会内联字体和图片PNG 导出会创建全页位图PDF 会进入打印布局。十兆正文若继续走这些路径峰值很难用单一阈值控制。因此产品没有保留一个“仍然试试”的入口。命令面板与右键菜单显示禁用底层prepareOutput再拒绝。用户可以先拆分文档或保存后用批处理工具处理。对专业 PC 软件而言明确的能力边界比不可预测的偶尔成功更专业。超长单行是另一类风险总字符数相同十万行短文本与一行十兆文本的布局成本不同。关闭lineWrapping能减少超长行的视觉测量但横向滚动、选择、查找和行列定位仍需要专项测试。当前十兆语料包含短行不能代表压缩 JSON、日志和生成代码。后续性能矩阵至少要加入全中文短行、英文日志、单个超长行、CRLF、混合换行、BOM、稀疏超长链接以及接近阈值的频繁编辑。每种语料记录首次可交互、输入 P95、滚动帧、撤销耗时和保存时长。一个平均样本不足以定义“大文件”。真机验收应测什么真机测试需要从文件选择器开始而不是在已加载页面中调用setDocument。计时边界应分成选择完成到源码首屏、源码首屏到可输入、一次输入到字符显示、保存发起到fsync完成。还应记录 ArkUI 主进程与 ArkWeb 进程组 PSS而不是只看单进程内存。设备矩阵至少覆盖低内存配置与目标鸿蒙 PC输入法包含中文拼音和英文键盘窗口包含停靠侧栏与窄窗口。冷启动、热启动、冷文件缓存和热缓存分别统计 P50/P95。测试完成后校验源文件哈希或字节内容不能以“窗口没崩”代替数据正确。恢复能力的后续方向大文档模式当前暂停周期全文恢复这是诚实但仍可改进的边界。更适合的方向是增量操作日志记录基线文件指纹、文档修订号和有限 transaction在恢复时重放并定期压缩检查点。任何方案都必须处理外部修改、换行格式、撤销历史和异常中断。增量恢复不能只在正常退出路径测试。需要模拟写到一半、检查点损坏、基线文件被外部替换、日志重复和空间不足。直到这些失败路径证明可靠现有策略仍应优先保留源码编辑、主动保存和关闭确认不提前承诺“十兆文档也有完整秒级恢复”。产品优势来自稳定而不是强行全功能大文档场景中用户通常更看重能打开、能搜索局部、能修改和能保存而不是公式是否即时渲染。OhMarkdown 的保护模式把核心任务排在增强任务之前避免渲染插件拖垮文件工具。这种优先级与本地优先、安全保存和冲突处理共同构成可靠性优势。优势还来自指标诚实。当前 87 ms 是 Web 页面内测量历史模拟器整链约 345 ms 也不能替代 Release 真机 P95十兆代码单元不是十兆 UTF-8 字节自动化通过不代表无限文件支持。明确这些边界让后续优化有真实基线也防止产品宣传透支工程信誉。结论鸿蒙 PC Markdown 编辑器的大文档能力不是让所有增强功能在十兆正文上继续运行而是在资源预算被突破时保住源码和保存。OhMarkdown 在 EditorState 创建之前选择minimalSetup统一拒绝预览与导出停止高成本字数和恢复快照并用精确十兆级代码单元样本验证三秒内进入保护模式。当前 Playwright44/44通过目标用例记录 87 ms界面保持源码可见、预览隐藏。这个结果建立了 Web 保护路径基线但完整 UTF-8 文件读取、超长单行、中文输入、真机 P95、进程组内存和大文档增量恢复仍需继续验证。可靠的产品优势来自知道哪些能力必须保住也来自清楚说明哪些能力尚未证明。