<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>性能预算 | 锤子前端</title><description>Now vibe coding, so learning hammer FE ?</description><link>https://channel.meo-ai.com</link><item><title>《设计系统应该默认就是快的》</title><link>https://channel.meo-ai.com/posts/730</link><guid isPermaLink="true">https://channel.meo-ai.com/posts/730</guid><pubDate>Thu, 29 Oct 2026 09:14:04 GMT</pubDate><content:encoded>&lt;span class=&quot;post-title-source&quot;&gt;《设计系统应该默认就是快的》&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;标签：&lt;br /&gt;&lt;a href=&quot;/search/result?q=%23%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91&quot; title=&quot;#前端开发&quot;&gt;#前端开发&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E8%AE%BE%E8%AE%A1%E7%B3%BB%E7%BB%9F%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96&quot; title=&quot;#设计系统性能优化&quot;&gt;#设计系统性能优化&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95&quot; title=&quot;#性能测试&quot;&gt;#性能测试&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E6%80%A7%E8%83%BD%E9%A2%84%E7%AE%97&quot; title=&quot;#性能预算&quot;&gt;#性能预算&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23WebComponents&quot; title=&quot;#WebComponents&quot;&gt;#WebComponents&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E7%BB%84%E4%BB%B6%E6%B8%B2%E6%9F%93%E4%BC%98%E5%8C%96&quot; title=&quot;#组件渲染优化&quot;&gt;#组件渲染优化&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;总结：&lt;br /&gt;这篇文章通过实测十大主流开源设计系统（Mantine、Ant Design、Material UI、React Spectrum、Carbon、Fluent、Web Awesome、UI5、Spectrum Web Components、Ionic），论证了性能应当与设计系统团队所重视的可达性（accessibility）平起平坐：底层组件的每一个性能修复，都会同时惠及所有基于该设计系统构建的应用。测试发现性能优劣并不取决于框架本身，而在于具体实现细节，作者还深入剖析了 Ionic、Ant Design、UI5、React Spectrum 等慢速组件的根因，并给出了可行的修复建议，最后提供了基于 Playwright 的自动化性能测试方案与「Fast by Default（默认即快）」的理念。&lt;br /&gt;&lt;br /&gt;文章要点：&lt;br /&gt;1. 浏览器的 JavaScript 主线程是所有层共用的，设计系统组件越慢，留给应用代码的余地就越小——修复一个设计系统组件的性能，等于同时提升所有依赖它的应用。&lt;br /&gt;2. 作者选取了十个基于不同框架（React、Lit、FAST、Stencil、SAP 自研框架）的设计系统，在 4 倍 CPU 降速、Chrome 155 环境下实测了两大典型场景：打开含 249 个国家的下拉选择器、一次性全选 100 个复选框。&lt;br /&gt;3. 实测结果差异巨大：国家选择器从最快 Fluent 的 61ms 到最慢 Ionic 的 1,266ms（比第二名慢 5 倍以上）；复选框从 Fluent 的 29ms 到 Ant Design 的 421ms——同一框架（如 React 或 Lit）内部差距同样悬殊，性能问题出在实现而非框架。&lt;br /&gt;4. 十个设计系统中只有 Spectrum Web Components 在每个 PR 上自动跑组件级性能基准，多数团队只检查包体积——但包体积与组件在页面上的响应速度并无直接关系。&lt;br /&gt;5. 作者逐一剖析了慢速根因：Ionic 因 Stencil 在无 shadow DOM 的场景下用 &lt;code&gt;appendChildSlotFix&lt;/code&gt; 模拟插槽、每次新增选项都要遍历全部既有子节点三次（O(n²)）；React Spectrum 因 React Aria 逐个清空高度再读取尺寸造成「布局抖动」；UI5 因隐藏弹层中预置全部 249 个选项，打开瞬间浏览器要一次性完成约 1500 个元素的样式计算；Ant Design 的慢则主要来自 100 个复选框同时触发的颜色渐变动画。&lt;br /&gt;6. 性能瓶颈各有解法：长列表用虚拟滚动（Ant Design 的做法值得借鉴，还为屏幕阅读器保留了高亮项的隐藏副本）；动画改由合成器线程运行的 opacity 渐变替代主线程上的颜色渐变；Stencil 可直接修复插槽回退内容的第三次检查，作者实测去掉后加 2000 个元素快约 7 倍。&lt;br /&gt;7. 作者分享了用 Playwright + Chrome DevTools 协议（CPU 降速 4 倍 + Long Animation Frames 长帧 API）编写组件性能测试的完整代码，包含「总耗时预算 300ms」和「最长无响应帧不超过 100ms」两条性能预算（performance budget），以及一条「选项翻倍时耗时增长不超过 2.5 倍」的防 O(n²) 回归测试。&lt;br /&gt;8. 落地的最佳实践是「默认就提供快的行为」：超过性能预算的列表自动切换虚拟化、复选框仅在被直接点击时才播放动画，并在文档中写明每个组件的测试数据规模上限，发布说明中给出修复前后的量化数据（如「500 个选项下打开从 300ms 降到 150ms」）。&lt;br /&gt;9. 以上测试代码已开源在 GitHub 仓库 design-system-performance-tests 中，可直接复制改造用于自己的设计系统，并附带 GitHub Actions 工作流实现每个 PR 自动跑性能测试。&lt;br /&gt;10. 文章结尾宣传了作者的新书《Fast by Default: Practical Performance Engineering》（Manning 早期访问版），把这套思路延伸到后端与移动端。&lt;br /&gt;&lt;br /&gt;URL：&lt;a href=&quot;https://denodell.com/blog/design-systems-should-be-fast-by-default&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; title=&quot;https://denodell.com/blog/design-systems-should-be-fast-by-default&quot;&gt;https://denodell.com/blog/design-systems-should-be-fast-by-default&lt;/a&gt;&lt;a class=&quot;tgme_widget_message_link_preview&quot; href=&quot;https://denodell.com/blog/design-systems-should-be-fast-by-default&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; title=&quot;If a design system’s components are slow to interact with, so are any apps built with it. I timed large dropdowns and checkbox lists in some popular design systems, worked out how to make the slow ones faster, and wrote tests that fail when they’re too slow.&quot;&gt;
  
  &lt;div class=&quot;link_preview_site_name accent_color&quot;&gt;Den Odell&lt;/div&gt;
  &lt;img class=&quot;link_preview_image&quot; alt=&quot;Design Systems Should Be Fast by Default&quot; src=&quot;/static/https://cdn4.telesco.pe/file/prwDcUJjanfw3iDWSDKbwkdZNnwMgqXd8jse5-sGrIQFZEQ-bM__2cCdCrCKuuMxJn8qbhJIz27feWIXXSJ4RzrlsYlA0KbHp-HDqYfd-XCo_hd1SFHnRsM0VKHnl6faIKdO3Ga2GjMP5NPqFysbIFdTXxI4IQ8sbshAgYrFsSX8KuwMxYAFyVjPKL7AMRowWXal7pJwDx3cCUyRUqdEyPKWxsgr5-_k1pGbKifxUOOqggDzd_sFGafjxxdFuTkkb3JRwMGQhTANx-8Mlia_Qqw7mYYIoG7WpJLcJT2ZKFKG6vPWDSvUSsh84ousi-MwLEF8zrTeP8bDLgBQ0p6tXQ.jpg&quot; width=&quot;1200&quot; height=&quot;630&quot; loading=&quot;eager&quot; /&gt;
  &lt;div class=&quot;link_preview_title&quot;&gt;Design Systems Should Be Fast by Default&lt;/div&gt;
  &lt;div class=&quot;link_preview_description&quot;&gt;If a design system’s components are slow to interact with, so are any apps built with it. I timed large dropdowns and checkbox lists in some popular design systems, worked out how to make the slow ones faster, and wrote tests that fail when they’re too slow.&lt;/div&gt;
&lt;/a&gt;</content:encoded></item><item><title>《在 GitHub Copilot 应用中流畅渲染超大 Pull Request》</title><link>https://channel.meo-ai.com/posts/713</link><guid isPermaLink="true">https://channel.meo-ai.com/posts/713</guid><pubDate>Sat, 26 Sep 2026 23:54:52 GMT</pubDate><content:encoded>&lt;span class=&quot;post-title-source&quot;&gt;《在 GitHub Copilot 应用中流畅渲染超大 Pull Request》&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;标签：&lt;br /&gt;&lt;a href=&quot;/search/result?q=%23%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B&quot; title=&quot;#软件工程&quot;&gt;#软件工程&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E5%89%8D%E7%AB%AF%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96&quot; title=&quot;#前端性能优化&quot;&gt;#前端性能优化&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23PullRequest&quot; title=&quot;#PullRequest&quot;&gt;#PullRequest&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E8%99%9A%E6%8B%9F%E5%8C%96%E6%B8%B2%E6%9F%93&quot; title=&quot;#虚拟化渲染&quot;&gt;#虚拟化渲染&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23React&quot; title=&quot;#React&quot;&gt;#React&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E6%B5%8B%E9%87%8F%E8%B0%83%E5%BA%A6&quot; title=&quot;#测量调度&quot;&gt;#测量调度&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E6%BB%9A%E5%8A%A8%E9%94%9A%E5%AE%9A&quot; title=&quot;#滚动锚定&quot;&gt;#滚动锚定&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E6%80%A7%E8%83%BD%E7%9B%91%E6%8E%A7&quot; title=&quot;#性能监控&quot;&gt;#性能监控&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;总结：&lt;br /&gt;文章介绍了 GitHub Copilot 应用如何重构 Pull Request 视图，使其能够流畅处理包含 2,200 个文件、超过 100 万行代码变更和 400 多条内联评论的超大型 PR。核心挑战在于评论高度的动态性——与代码行不同，评论高度取决于 Markdown 换行、可展开区块、回复框和图片加载等渲染时才能确定的因素。团队通过分离确定性与动态几何、实现智能测量调度器、采用滚动锚定技术，并建立自动化测量循环来解决这一问题，最终实现了百万行 diff 的流畅浏览体验。&lt;br /&gt;&lt;br /&gt;文章要点：&lt;br /&gt;&lt;br /&gt;1. &lt;b&gt;代码与评论的几何分离&lt;/b&gt;：代码行高度固定且可预先计算，而评论高度动态变化。团队将文档高度分为确定性代码高度（精确前缀和）和动态块高度（估算后测量），两者独立管理，避免评论调整时重建整个代码几何。&lt;br /&gt;&lt;br /&gt;2. &lt;b&gt;智能测量调度器&lt;/b&gt;：放弃每块一个 ResizeObserver 的方案（会触发反馈循环），改为单一的空闲和滚动门控测量通道。仅在视口附近约 2400px 范围内进行测量，屏幕上的块优先批量读取，离屏块最多做一次有限渲染，超过视口高度的块跳过测量。&lt;br /&gt;&lt;br /&gt;3. &lt;b&gt;滚动锚定技术&lt;/b&gt;：当测量高度与估算不符时，通过身份而非像素来校正——记录用户锚定的行或块，应用高度增量后，将同一锚点解析到新像素位置并滚动，确保用户视线不跳动。区分用户滚动与程序滚动，避免侧边栏切换等操作误触发保护机制。&lt;br /&gt;&lt;br /&gt;4. &lt;b&gt;数据管道优化&lt;/b&gt;：流式传输结构优先于内容，文件树和元数据在文档加载时即可渲染；语法高亮在主线程外运行，行先以纯文本显示；释放文档时保留最近几个 diff 的缓存，平衡内存与返回时的加载速度。&lt;br /&gt;&lt;br /&gt;5. &lt;b&gt;自动化测量循环&lt;/b&gt;：建立&quot;变更→测量→改进&quot;的无人值守循环，包括无头探针车道（声明式流程 + 生产环境插桩）和自动驾驶仪（驱动真实桌面应用），通过健康信号（如无未填充间隙、评论块非空）自动检测问题，实现机械式调试而非人工复现。&lt;br /&gt;&lt;br /&gt;URL：&lt;br /&gt;&lt;a href=&quot;https://github.blog/engineering/user-experience/rendering-huge-pull-requests-in-the-github-copilot-app/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; title=&quot;https://github.blog/engineering/user-experience/rendering-huge-pull-requests-in-the-github-copilot-app/&quot;&gt;https://github.blog/engineering/user-experience/rendering-huge-pull-requests-in-the-github-copilot-app/&lt;/a&gt;&lt;a class=&quot;tgme_widget_message_link_preview&quot; href=&quot;https://github.blog/engineering/user-experience/rendering-huge-pull-requests-in-the-github-copilot-app&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; title=&quot;How we rebuilt the diff surface in the GitHub Copilot app to open a million-line pull request with hundreds of inline review comments.&quot;&gt;
  
  &lt;div class=&quot;link_preview_site_name accent_color&quot;&gt;The GitHub Blog&lt;/div&gt;
  &lt;img class=&quot;link_preview_image&quot; alt=&quot;Rendering huge pull requests in the GitHub Copilot app&quot; src=&quot;/static/https://cdn4.telesco.pe/file/Q0e6XCy4GREe5APpCJ0_bG8D7plewPDXZ0hOGWczxwxKYLRaDieMV2SFTC2_VsffSvc68IJy_EE7N0hWt6obHCbDcB7AqLxgmsf_SnKQlcb0FtcO1Z4Ss5KpTVtFGlctYtgOkZOu_7kKZxiMZoqHhr2Yod-hCeNOSxlP7QSUPkDiYNsakYKauC-cRnRgLdmaKpYUAmmSnsWRBcrcWDVTCQ1DqrdWm7ekEr60xsIWQdmCENdNNmv0EV3s_Lt-nl09t2wBa3avHjdmaD1dRPJSLolpITbqM9JdutIsD7Q0624iueRS7ZhEg2ZKOTeB-jXwp-KIrev8BevUBEPog2DNKA.jpg&quot; width=&quot;1200&quot; height=&quot;630&quot; loading=&quot;eager&quot; /&gt;
  &lt;div class=&quot;link_preview_title&quot;&gt;Rendering huge pull requests in the GitHub Copilot app&lt;/div&gt;
  &lt;div class=&quot;link_preview_description&quot;&gt;How we rebuilt the diff surface in the GitHub Copilot app to open a million-line pull request with hundreds of inline review comments.&lt;/div&gt;
&lt;/a&gt;</content:encoded></item><item><title>《浏览器主线程很昂贵：高性能前端优化实战指南》</title><link>https://channel.meo-ai.com/posts/706</link><guid isPermaLink="true">https://channel.meo-ai.com/posts/706</guid><pubDate>Thu, 10 Sep 2026 23:29:33 GMT</pubDate><content:encoded>&lt;span class=&quot;post-title-source&quot;&gt;《浏览器主线程很昂贵：高性能前端优化实战指南》&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;标签：&lt;br /&gt;&lt;a href=&quot;/search/result?q=%23%E5%89%8D%E7%AB%AF&quot; title=&quot;#前端&quot;&gt;#前端&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23Web%E6%80%A7%E8%83%BD&quot; title=&quot;#Web性能&quot;&gt;#Web性能&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86&quot; title=&quot;#浏览器原理&quot;&gt;#浏览器原理&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23JavaScript&quot; title=&quot;#JavaScript&quot;&gt;#JavaScript&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E6%B8%B2%E6%9F%93%E7%AE%A1%E7%BA%BF&quot; title=&quot;#渲染管线&quot;&gt;#渲染管线&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23WebWorker&quot; title=&quot;#WebWorker&quot;&gt;#WebWorker&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E5%8A%A8%E7%94%BB%E4%BC%98%E5%8C%96&quot; title=&quot;#动画优化&quot;&gt;#动画优化&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E4%BA%A4%E4%BA%92%E4%BC%98%E5%8C%96&quot; title=&quot;#交互优化&quot;&gt;#交互优化&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E6%80%A7%E8%83%BD%E8%B0%83%E4%BC%98&quot; title=&quot;#性能调优&quot;&gt;#性能调优&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;总结：&lt;br /&gt;&lt;br /&gt;本文深入剖析了浏览器主线程作为稀缺资源的工作原理，指出前端性能问题的根源往往不是代码速度慢，而是主线程被长时间占用导致界面冻结。文章系统性地介绍了两大类优化策略：在主线程上&quot;精打细算&quot;（拆分、批处理、优先级排序、延迟执行），以及&quot;完全不用主线程&quot;（利用合成器线程、Web Worker、消除不必要的工作），并通过大量交互式 Demo 帮助读者直观理解每种技术的实际效果。&lt;br /&gt;&lt;br /&gt;文章要点：&lt;br /&gt;&lt;br /&gt;1. &lt;b&gt;主线程是性能瓶颈的核心&lt;/b&gt;：主线程同时负责运行 JavaScript、样式计算、布局、绘制和事件处理，所有工作排队串行执行。60Hz 屏幕每帧预算约 16.6ms，实际可用仅约 10ms，超过 50ms 的任务会导致界面卡顿。&lt;br /&gt;&lt;br /&gt;2. &lt;b&gt;拆分（Splitting）&lt;/b&gt;：将大任务切割成小片段，通过 &lt;code&gt;setTimeout&lt;/code&gt; 或 &lt;code&gt;requestAnimationFrame&lt;/code&gt; 让出主线程，让浏览器在间隙处理渲染和输入。注意过度拆分会产生额外开销，且 &lt;code&gt;JSON.parse&lt;/code&gt; 等原子操作无法拆分。&lt;br /&gt;&lt;br /&gt;3. &lt;b&gt;批处理（Batching）&lt;/b&gt;：将频繁触发的事件（如滚动、输入）合并执行，使用防抖（debounce）和节流（throttle）减少重复劳动。React 的虚拟 DOM 本质上也是一种批处理机制。&lt;br /&gt;&lt;br /&gt;4. &lt;b&gt;优先级排序（Prioritizing）&lt;/b&gt;：通过自定义队列（基于 &lt;code&gt;MessageChannel&lt;/code&gt;）实现任务插队机制，确保用户当前关注的操作（如点击预览图片）优先执行，采用&quot;空闲时预处理，紧急时优先处理&quot;的策略。&lt;br /&gt;&lt;br /&gt;5. &lt;b&gt;延迟执行（Deferring）&lt;/b&gt;：非必要工作延后处理，包括代码分割、使用 &lt;code&gt;IntersectionObserver&lt;/code&gt; 实现虚拟列表（只渲染可视区域内容）、离屏时暂停动画等，避免一次性处理全部数据。&lt;br /&gt;&lt;br /&gt;6. &lt;b&gt;利用合成器线程&lt;/b&gt;：使用 &lt;code&gt;transform&lt;/code&gt; 和 &lt;code&gt;opacity&lt;/code&gt; 代替 &lt;code&gt;top&lt;/code&gt;、&lt;code&gt;left&lt;/code&gt;、&lt;code&gt;width&lt;/code&gt; 等触发布局的属性做动画，让动画在合成器线程运行，即使主线程繁忙也能保持流畅。&lt;br /&gt;&lt;br /&gt;7. &lt;b&gt;FLIP 动画技术&lt;/b&gt;：对于必须改变布局的动画（如列表重排），先测量初始和最终位置，通过反转和播放 &lt;code&gt;transform&lt;/code&gt; 来实现平滑过渡，将布局计算限制为仅一次，动画过程交给合成器。&lt;br /&gt;&lt;br /&gt;8. &lt;b&gt;Web Worker 处理重计算&lt;/b&gt;：将图片处理、大数据解析等纯计算任务转移到 Worker 线程，通过 &lt;code&gt;postMessage&lt;/code&gt; 的 Transferable 对象（如 &lt;code&gt;ArrayBuffer&lt;/code&gt;）实现零拷贝数据传输，避免主线程冻结。&lt;br /&gt;&lt;br /&gt;9. &lt;b&gt;消除不必要的工作&lt;/b&gt;：当数据流入速度超过处理能力时，采用丢弃（旧日志）、合并（只保留最新值）、跳过（缓存 memoization）三种策略，从源头减少工作量。&lt;br /&gt;&lt;br /&gt;10. &lt;b&gt;避免布局抖动（Layout Thrashing）&lt;/b&gt;：不要交替读写布局属性（如 &lt;code&gt;offsetWidth&lt;/code&gt;），应先批量读取再批量写入，强制浏览器反复计算布局会严重阻塞主线程。&lt;br /&gt;&lt;br /&gt;URL：&lt;br /&gt;&lt;a href=&quot;https://kciter.so/posts/the-expensive-main-thread/en/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; title=&quot;https://kciter.so/posts/the-expensive-main-thread/en/&quot;&gt;https://kciter.so/posts/the-expensive-main-thread/en/&lt;/a&gt;&lt;a class=&quot;tgme_widget_message_link_preview&quot; href=&quot;https://kciter.so/posts/the-expensive-main-thread/en&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; title=&quot;What comes to mind when you hear &amp;quot;frontend optimization&amp;quot;? For most of us it&apos;s things like reducing network requests, shrinking the bundle,…&quot;&gt;
  
  &lt;div class=&quot;link_preview_site_name accent_color&quot;&gt;kciter.so&lt;/div&gt;
  &lt;img class=&quot;link_preview_image&quot; alt=&quot;The Browser&apos;s Main Thread Is Expensive | kciter.so&quot; src=&quot;/static/https://cdn4.telesco.pe/file/M7yU5vwQA68lMlS1cfdCD6jbRYwY9CREzH7USkG-XnIJ-92aRhup9RXNnO-g64Vxfap3MjPkx0cCo96NP-RjpcI4H_rJwlcDlA62JBGitYmRKNXswN5xB4H1dzZdCGIfT0fIBu6d73jdr1NkSwaqfMPt5I0Z9eoElaT8S5nD0XHwSDcuryH0fAIblnFZ66jz_7tyCgmbw6VRF3GGck-RnU6dkTlCk1pUUVszRfFsL5eDWC_yqgUk3CO4OnE3hvOs2QOUFVDFoBUS1AFVf8mIT7eUh_DxBPiyesG1EIm1evmcWVms-2Fe3vtSm7qBfY004nIb5_5hD1C9jR0NfF-HHQ.jpg&quot; width=&quot;1200&quot; height=&quot;630&quot; loading=&quot;eager&quot; /&gt;
  &lt;div class=&quot;link_preview_title&quot;&gt;The Browser&apos;s Main Thread Is Expensive | kciter.so&lt;/div&gt;
  &lt;div class=&quot;link_preview_description&quot;&gt;What comes to mind when you hear &quot;frontend optimization&quot;? For most of us it&apos;s things like reducing network requests, shrinking the bundle,…&lt;/div&gt;
&lt;/a&gt;</content:encoded></item><item><title>《关于协作编辑的谎言（第二部分）：为什么我们不用Yjs》</title><link>https://channel.meo-ai.com/posts/575</link><guid isPermaLink="true">https://channel.meo-ai.com/posts/575</guid><pubDate>Wed, 18 Mar 2026 01:39:20 GMT</pubDate><content:encoded>&lt;span class=&quot;post-title-source&quot;&gt;《关于协作编辑的谎言（第二部分）：为什么我们不用Yjs》&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;标签：&lt;a href=&quot;/search/result?q=%23%E5%89%8D%E7%AB%AF&quot; title=&quot;#前端&quot;&gt;#前端&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23ProseMirror&quot; title=&quot;#ProseMirror&quot;&gt;#ProseMirror&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23CRDT&quot; title=&quot;#CRDT&quot;&gt;#CRDT&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E5%8D%8F%E4%BD%9C%E7%BC%96%E8%BE%91&quot; title=&quot;#协作编辑&quot;&gt;#协作编辑&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96&quot; title=&quot;#性能优化&quot;&gt;#性能优化&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23Yjs&quot; title=&quot;#Yjs&quot;&gt;#Yjs&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E5%AE%9E%E6%97%B6%E5%8D%8F%E4%BD%9C&quot; title=&quot;#实时协作&quot;&gt;#实时协作&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;总结：&lt;br /&gt;本文是Moment.dev团队关于协作编辑算法分析的第二部分，作者详细阐述了为何在生产环境中放弃Yjs而选择基于ProseMirror-collab的简单方案。文章指出Yjs存在严重的性能问题（每次协作编辑会销毁重建整个文档）、与文档Schema冲突、权限控制困难、调试困难以及墓碑数据占用内存等问题。作者认为，除非真正需要无主节点的P2P架构，否则40行代码的&quot;简单方案&quot;在性能、可维护性和开发体验上都优于复杂的CRDT实现。&lt;br /&gt;&lt;br /&gt;文章要点：&lt;br /&gt;- Yjs存在严重性能缺陷：每次协作编辑会销毁并重建整个文档，导致60fps目标难以达成，影响NodeView、插件状态、撤销功能和光标位置管理&lt;br /&gt;- 简单方案仅需40行代码：使用prosemirror-collab库，通过单一权威节点管理文档版本和事务，支持乐观更新、离线编辑和网络中断恢复&lt;br /&gt;- Yjs与文档Schema冲突：在无主节点架构下难以验证事务有效性，可能导致数据永久丢失，升级时尤其危险&lt;br /&gt;- 权限控制复杂化：需要将Yjs的XML更新预测转换为ProseMirror事务来判断权限，实现难度大&lt;br /&gt;- 墓碑数据问题：Yjs需保留删除标记，导致内存持续增长或数据丢失风险，而简单方案通过数据库存储步骤即可解决&lt;br /&gt;- 调试困难：CRDT仅保证最终一致性，难以区分暂时分歧与真正错误，调试工具受限&lt;br /&gt;- 核心观点：技术选型应从最终用户体验出发，而非算法本身；如无P2P刚需，简单方案在各方面均优于CRDT&lt;br /&gt;&lt;br /&gt;文章URL：&lt;a href=&quot;https://www.moment.dev/blog/lies-i-was-told-pt-2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; title=&quot;https://www.moment.dev/blog/lies-i-was-told-pt-2&quot;&gt;https://www.moment.dev/blog/lies-i-was-told-pt-2&lt;/a&gt;&lt;a class=&quot;tgme_widget_message_link_preview&quot; href=&quot;https://moment.dev/blog/lies-i-was-told-pt-2&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
  
  &lt;div class=&quot;link_preview_site_name accent_color&quot;&gt;Lies I was Told About Collaborative Editing, Part 2: Why we don&apos;t use Yjs / Moment devlog&lt;/div&gt;
  &lt;img class=&quot;link_preview_image&quot; alt=&quot;Lies I was Told About Collaborative Editing, Part 2: Why we don&apos;t use Yjs / Moment devlog&quot; src=&quot;/static/https://cdn4.telesco.pe/file/YVXaUzBE8-9TDW2QQrSSbabfgg71zJ4YfK9str6-S1LPODRrO0GTgZm9XVC005_t5HR8VqdNrsgcUwQyA9CcsGyd1JTNXiYmfD35KPvxoWVvTV3w40qwfsqy8doKw0ZtWIufS8kkP6b_7C_qBXZmPDelkDueKKd_mZLaVGpRdnWPevjv76nE543DoXGcMtepNx9ppudeaLhaphSNg-17nX4wJVoKz43YqT9z_ynPXioKsnRqKvzAi1NxlO07pXRzyhwn5GcDxgfJ6WE6NlLa5PhPeeJh7VLRKBwCq1-crT8pqRc_IVTVDnEToydSWbK2EBXIWObDBA27HcLh3qeT-Q.jpg&quot; width=&quot;1200&quot; height=&quot;630&quot; loading=&quot;eager&quot; /&gt;
  
  
&lt;/a&gt;</content:encoded></item><item><title>《理解 React Fiber 存在的意义》</title><link>https://channel.meo-ai.com/posts/571</link><guid isPermaLink="true">https://channel.meo-ai.com/posts/571</guid><pubDate>Mon, 09 Mar 2026 01:16:23 GMT</pubDate><content:encoded>&lt;span class=&quot;post-title-source&quot;&gt;《理解 React Fiber 存在的意义》&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;标签：&lt;a href=&quot;/search/result?q=%23%E5%89%8D%E7%AB%AF&quot; title=&quot;#前端&quot;&gt;#前端&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23React&quot; title=&quot;#React&quot;&gt;#React&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23React_Fiber&quot; title=&quot;#React_Fiber&quot;&gt;#React_Fiber&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96&quot; title=&quot;#性能优化&quot;&gt;#性能优化&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E5%B9%B6%E5%8F%91%E6%B8%B2%E6%9F%93&quot; title=&quot;#并发渲染&quot;&gt;#并发渲染&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23Virtual_DOM&quot; title=&quot;#Virtual_DOM&quot;&gt;#Virtual_DOM&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;总结（一段话概括）&lt;br /&gt;React Fiber 是 React 16 对核心协调算法的彻底重写，旨在解决 React 15 中 Stack Reconciler 同步递归更新导致的主线程阻塞问题。通过将组件树重构为链表结构的 Fiber 节点，React 实现了可中断的异步更新、任务优先级调度和时间切片机制，使高优先级任务（如用户输入）能插队执行，避免页面卡顿，并为 Concurrent Mode、Suspense 等现代特性奠定基础。&lt;br /&gt;&lt;br /&gt;文章要点：&lt;br /&gt;- React 15 的瓶颈：Stack Reconciler 采用递归遍历，更新一旦开始无法中断，复杂组件树会导致主线程长时间阻塞，造成掉帧和交互卡顿&lt;br /&gt;- Fiber 的本质：将同步更新改为可中断的异步更新，每个 Fiber 节点是一个执行单元，通过 &lt;code&gt;child&lt;/code&gt;、&lt;code&gt;sibling&lt;/code&gt;、&lt;code&gt;return&lt;/code&gt; 指针形成链表树，取代递归调用栈&lt;br /&gt;- 时间切片（Time Slicing）：利用 &lt;code&gt;requestIdleCallback&lt;/code&gt;  polyfill（基于 MessageChannel），在浏览器每帧（16.6ms）中预留时间（默认 5ms）给 React，超时即让出主线程控制权&lt;br /&gt;- 优先级调度：引入 Lanes 机制，区分 Immediate（最高）、UserBlocking、Normal、Low、Idle 五级优先级，确保紧急更新优先处理&lt;br /&gt;- 双缓冲机制：维护 &lt;code&gt;current Fiber&lt;/code&gt; 和 &lt;code&gt;workInProgress Fiber&lt;/code&gt; 两棵树，通过 &lt;code&gt;alternate&lt;/code&gt; 指针关联，渲染完成后直接切换指针指向，避免重复创建对象&lt;br /&gt;- Phase 分离：将更新分为 Render 阶段（可中断，构建 Fiber 树）和 Commit 阶段（不可中断，同步执行 DOM 操作），支持错误边界（Error Boundaries）捕获&lt;br /&gt;- 架构演进：从 React 15 的两层（Reconciler + Renderer）增至 React 16+ 的三层（Scheduler + Reconciler + Renderer），调度器负责任务分配和中断控制&lt;br /&gt;&lt;br /&gt;文章URL：&lt;a href=&quot;https://inside-react.vercel.app/blog/understanding-why-react-fiber-exists&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; title=&quot;https://inside-react.vercel.app/blog/understanding-why-react-fiber-exists&quot;&gt;https://inside-react.vercel.app/blog/understanding-why-react-fiber-exists&lt;/a&gt;&lt;a class=&quot;tgme_widget_message_link_preview&quot; href=&quot;https://inside-react.vercel.app/blog/understanding-why-react-fiber-exists&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; title=&quot;Understanding Why React Fiber Exists and how it lets React pause, prioritize&quot;&gt;
  
  &lt;div class=&quot;link_preview_site_name accent_color&quot;&gt;reactjs maxxing&lt;/div&gt;
  &lt;img class=&quot;link_preview_image&quot; alt=&quot;Understanding Why React Fiber Exists&quot; src=&quot;/static/https://cdn4.telesco.pe/file/ST38agKU0K3enfmBXxim68bxFU7cKlV33MAUslVFBQNesHvHG7uqYkEp-LS296E7r-27TJ9xCiQsu7QpkYRmI5bISb8O_ncAVuW3a7FAuE_pnhAjTbPaKIH3mPx-I6JrN-RA8K71LDJ1fpYKaSCm0Y-8mnOaI_wGwOK2BbpGVl-1-3XPn6cOpQP6Oc9yjbluuKxMuedntk_w6rMfaCurne9iUnap6OeVkbks3QZ-aOC7aLWlCoML9M5kBPRJ6GdK3fYVmK2X3T-bB_gUIk5_judKvzm3UlQKCG2jSw6bsbx4JzkkK02z2YTCJLhm7sSPUe14JJjzgZ7A9kue7PuLwg.jpg&quot; width=&quot;1200&quot; height=&quot;630&quot; loading=&quot;eager&quot; /&gt;
  &lt;div class=&quot;link_preview_title&quot;&gt;Understanding Why React Fiber Exists&lt;/div&gt;
  &lt;div class=&quot;link_preview_description&quot;&gt;Understanding Why React Fiber Exists and how it lets React pause, prioritize&lt;/div&gt;
&lt;/a&gt;</content:encoded></item></channel></rss>