[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"i-ri:search-line":3,"i-ri:moon-line":8,"i-ri:sun-line":10,"i-ri:menu-3-line":12,"i-ri:close-line":14,"notes-module-items-react":16,"notes-page-react-12-rendering-and-delivery\u002F04-streaming-ssr-with-suspense":494,"i-ri:arrow-left-s-line":1946,"i-ri:menu-2-line":1948,"i-ri:arrow-right-s-line":1950,"i-ep:copy-document":1952},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":7},0,24,false,"\u003Cpath fill=\"currentColor\" d=\"m18.031 16.617l4.283 4.282l-1.415 1.415l-4.282-4.283A8.96 8.96 0 0 1 11 20c-4.968 0-9-4.032-9-9s4.032-9 9-9s9 4.032 9 9a8.96 8.96 0 0 1-1.969 5.617m-2.006-.742A6.98 6.98 0 0 0 18 11c0-3.867-3.133-7-7-7s-7 3.133-7 7s3.133 7 7 7a6.98 6.98 0 0 0 4.875-1.975z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":9},"\u003Cpath fill=\"currentColor\" d=\"M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2h.1A6.98 6.98 0 0 0 10 7m-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938A8 8 0 0 0 4 12\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":11},"\u003Cpath fill=\"currentColor\" d=\"M12 18a6 6 0 1 1 0-12a6 6 0 0 1 0 12m0-2a4 4 0 1 0 0-8a4 4 0 0 0 0 8M11 1h2v3h-2zm0 19h2v3h-2zM3.515 4.929l1.414-1.414L7.05 5.636L5.636 7.05zM16.95 18.364l1.414-1.414l2.121 2.121l-1.414 1.414zm2.121-14.85l1.414 1.415l-2.121 2.121l-1.414-1.414zM5.636 16.95l1.414 1.414l-2.121 2.121l-1.414-1.414zM23 11v2h-3v-2zM4 11v2H1v-2z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":13},"\u003Cpath fill=\"currentColor\" d=\"M3 4h18v2H3zm6 7h12v2H9zm-6 7h18v2H3z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":15},"\u003Cpath fill=\"currentColor\" d=\"m12 10.587l4.95-4.95l1.414 1.414l-4.95 4.95l4.95 4.95l-1.415 1.414l-4.95-4.95l-4.949 4.95l-1.414-1.415l4.95-4.95l-4.95-4.95L7.05 5.638z\"\u002F>",[17,22,26,30,34,38,42,46,50,54,58,62,66,70,74,78,82,86,90,94,98,102,106,110,114,118,122,126,130,134,138,142,146,150,154,158,162,166,170,174,178,182,186,190,194,198,202,206,210,214,218,222,226,230,234,238,242,246,250,254,258,262,266,270,274,278,282,286,290,294,298,302,306,310,314,318,322,326,330,334,338,342,346,350,354,358,362,366,370,374,378,382,386,390,394,398,402,406,410,414,418,422,426,430,434,438,442,446,450,454,458,462,466,470,474,478,482,486,490],{"path":18,"title":19,"meta":20},"\u002Fnotes\u002Freact\u002F01-basics\u002F01-how-to-read-this-repo","如何阅读本仓库（学习路径与章节依赖）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},"2026-11-05T09:47:15.000Z",{"path":23,"title":24,"meta":25},"\u002Fnotes\u002Freact\u002F01-basics\u002F02-render-vs-commit","React 渲染两阶段：Render vs Commit（总览）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":27,"title":28,"meta":29},"\u002Fnotes\u002Freact\u002F01-basics\u002F03-update-pipeline-birdview","从“更新”到“页面变更”：一次 setState 的全链路鸟瞰",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":31,"title":32,"meta":33},"\u002Fnotes\u002Freact\u002F01-basics","基础入门（建议先读）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":35,"title":36,"meta":37},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F01-browser-multi-process","浏览器多进程架构",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":39,"title":40,"meta":41},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F02-event-loop-overview","事件循环概述",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":43,"title":44,"meta":45},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F03-call-stack","函数调用栈",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":47,"title":48,"meta":49},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F04-threads","线程介绍",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":51,"title":52,"meta":53},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F05-refresh-rate-and-queues","刷新率与执行队列",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":55,"title":56,"meta":57},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F06-settimeout","setTimeout 原理详解",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":59,"title":60,"meta":61},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F07-promise","Promise 原理详解",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":63,"title":64,"meta":65},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F08-event-loop-in-practice","事件循环机制（综合）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":67,"title":68,"meta":69},"\u002Fnotes\u002Freact\u002F02-event-loop\u002F09-priority-queues","优先级队列",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":71,"title":72,"meta":73},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F01-concept","并发模式：概念",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":75,"title":76,"meta":77},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F02-demo","案例演示并发模式",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":79,"title":80,"meta":81},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F03-high-priority-preemption","高优先级插队",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":83,"title":84,"meta":85},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F04-preemption-vs-interruption","插队的影响、与中断的区别",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":87,"title":88,"meta":89},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F05-shouldYield","中断条件：shouldYield",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":91,"title":92,"meta":93},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F06-react-tasks-and-queues","React 中的任务与队列",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":95,"title":96,"meta":97},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F07-ensureRootIsScheduled","ensureRootIsScheduled",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":99,"title":100,"meta":101},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F08-batch-updates-merge","合并多个更新触发",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":103,"title":104,"meta":105},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F09-taskQueue-lifecycle","taskQueue 队列循环的启动与结束",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":107,"title":108,"meta":109},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F10-time-slicing","时间切片是如何实现的",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":111,"title":112,"meta":113},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F11-workLoop-full","workLoop 循环完整逻辑",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":115,"title":116,"meta":117},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F12-priority-design","React 中的优先级设计",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":119,"title":120,"meta":121},"\u002Fnotes\u002Freact\u002F03-concurrent-mode\u002F13-lane-model","lane 模型",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":123,"title":124,"meta":125},"\u002Fnotes\u002Freact\u002F04-fiber\u002F01-three-node-types","三种节点对象",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":127,"title":128,"meta":129},"\u002Fnotes\u002Freact\u002F04-fiber\u002F02-fiberRootNode","FiberRootNode",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":131,"title":132,"meta":133},"\u002Fnotes\u002Freact\u002F04-fiber\u002F03-fiber-tree","Fiber 树",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":135,"title":136,"meta":137},"\u002Fnotes\u002Freact\u002F04-fiber\u002F04-initial-mount-build","Fiber 树初始构建过程",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":139,"title":140,"meta":141},"\u002Fnotes\u002Freact\u002F04-fiber\u002F05-workLoopConcurrent","workLoopConcurrent",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":143,"title":144,"meta":145},"\u002Fnotes\u002Freact\u002F04-fiber\u002F06-stack-and-workInProgress","栈结构 与 workInProgress",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":147,"title":148,"meta":149},"\u002Fnotes\u002Freact\u002F04-fiber\u002F07-executionContext","执行上下文 executionContext",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":151,"title":152,"meta":153},"\u002Fnotes\u002Freact\u002F04-fiber\u002F08-update-lanes","update lanes",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":155,"title":156,"meta":157},"\u002Fnotes\u002Freact\u002F04-fiber\u002F09-render-lanes","render lanes",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":159,"title":160,"meta":161},"\u002Fnotes\u002Freact\u002F04-fiber\u002F10-fiber-lanes","fiber lanes",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":163,"title":164,"meta":165},"\u002Fnotes\u002Freact\u002F04-fiber\u002F11-flags-appendix","附录：flags",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":167,"title":168,"meta":169},"\u002Fnotes\u002Freact\u002F05-hooks\u002F01-background","hook 背景",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":171,"title":172,"meta":173},"\u002Fnotes\u002Freact\u002F05-hooks\u002F02-categories","hook 分类",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":175,"title":176,"meta":177},"\u002Fnotes\u002Freact\u002F05-hooks\u002F03-closures","hook 与闭包",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":179,"title":180,"meta":181},"\u002Fnotes\u002Freact\u002F05-hooks\u002F04-hooks-and-fiber","hook 与 fiber",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":183,"title":184,"meta":185},"\u002Fnotes\u002Freact\u002F05-hooks\u002F05-renderWithHooks","renderWithHooks",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":187,"title":188,"meta":189},"\u002Fnotes\u002Freact\u002F05-hooks\u002F06-init-state-hook","初始化 State Hook",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":191,"title":192,"meta":193},"\u002Fnotes\u002Freact\u002F05-hooks\u002F07-init-effect-hook","初始化 effect Hook",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":195,"title":196,"meta":197},"\u002Fnotes\u002Freact\u002F05-hooks\u002F08-circular-linked-list","环形链表详解",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":199,"title":200,"meta":201},"\u002Fnotes\u002Freact\u002F05-hooks\u002F09-useReducer-vs-useState","useReducer 与 useState 的区别",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":203,"title":204,"meta":205},"\u002Fnotes\u002Freact\u002F05-hooks\u002F10-update-linked-list","update 链表",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":207,"title":208,"meta":209},"\u002Fnotes\u002Freact\u002F05-hooks\u002F11-mount-state-updates","初始阶段的状态更新",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":211,"title":212,"meta":213},"\u002Fnotes\u002Freact\u002F05-hooks\u002F12-baseQueue-vs-pending","baseQueue 与 queue.pending",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":215,"title":216,"meta":217},"\u002Fnotes\u002Freact\u002F05-hooks\u002F13-dispatch-in-update","更新阶段的 dispatch",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":219,"title":220,"meta":221},"\u002Fnotes\u002Freact\u002F05-hooks\u002F14-commitRoot","commitRoot",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":223,"title":224,"meta":225},"\u002Fnotes\u002Freact\u002F06-diff\u002F01-update-overview","React 更新机制概述",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":227,"title":228,"meta":229},"\u002Fnotes\u002Freact\u002F06-diff\u002F02-diff-strategy","diff 策略",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":231,"title":232,"meta":233},"\u002Fnotes\u002Freact\u002F06-diff\u002F03-node-compare","节点比较方式",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":235,"title":236,"meta":237},"\u002Fnotes\u002Freact\u002F06-diff\u002F04-reconcileChildFibers","reconcileChildFibers",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":239,"title":240,"meta":241},"\u002Fnotes\u002Freact\u002F06-diff\u002F05-reconcileSingleElement","reconcileSingleElement",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":243,"title":244,"meta":245},"\u002Fnotes\u002Freact\u002F06-diff\u002F06-reconcileChildrenArray","reconcileChildrenArray",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":247,"title":248,"meta":249},"\u002Fnotes\u002Freact\u002F06-diff\u002F07-why-not-number-key","为什么不建议使用数字作为 key",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":251,"title":252,"meta":253},"\u002Fnotes\u002Freact\u002F07-event-system\u002F01-overview","事件系统概述",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":255,"title":256,"meta":257},"\u002Fnotes\u002Freact\u002F07-event-system\u002F02-event-plugin","事件插件",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":259,"title":260,"meta":261},"\u002Fnotes\u002Freact\u002F07-event-system\u002F03-event-pooling","事件池",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":263,"title":264,"meta":265},"\u002Fnotes\u002Freact\u002F07-event-system\u002F04-root-listeners","根节点事件绑定",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":267,"title":268,"meta":269},"\u002Fnotes\u002Freact\u002F07-event-system\u002F05-event-dispatch","事件触发",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":271,"title":272,"meta":273},"\u002Fnotes\u002Freact\u002F08-interview\u002F01-useEffect-vs-useLayoutEffect","useEffect 与 useLayoutEffect 的区别",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":275,"title":276,"meta":277},"\u002Fnotes\u002Freact\u002F08-interview\u002F02-why-no-conditional-hooks","为什么 hook 不能写在条件判断里",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":279,"title":280,"meta":281},"\u002Fnotes\u002Freact\u002F08-interview\u002F03-understanding-concurrency","聊聊在 React 中，你对并发模式的理解",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":283,"title":284,"meta":285},"\u002Fnotes\u002Freact\u002F08-interview\u002F04-update-mechanism","聊聊 React 的更新机制原理",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":287,"title":288,"meta":289},"\u002Fnotes\u002Freact\u002F08-interview\u002F05-setState-sync-or-async","setState 是同步还是异步的？",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":291,"title":292,"meta":293},"\u002Fnotes\u002Freact\u002F08-interview\u002F06-useState-vs-useReducer","聊聊 useState 与 useReducer 的区别",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":295,"title":296,"meta":297},"\u002Fnotes\u002Freact\u002F08-interview\u002F07-closure-trap","聊聊闭包陷阱问题，以及如何解决",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":299,"title":300,"meta":301},"\u002Fnotes\u002Freact\u002F08-interview\u002F08-time-slicing-details","时间分片是如何实现的（任务拆分\u002F中断\u002F恢复）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":303,"title":304,"meta":305},"\u002Fnotes\u002Freact\u002F08-interview\u002F09-batched-updates-useState","聊聊 useState 的批处理更新机制",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":307,"title":308,"meta":309},"\u002Fnotes\u002Freact\u002F08-interview\u002F10-jsx-to-dom","JSX 是如何转变成为真实 DOM 的",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":311,"title":312,"meta":313},"\u002Fnotes\u002Freact\u002F08-interview\u002F11-useCallback-impl","useCallback 的实现原理是什么",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":315,"title":316,"meta":317},"\u002Fnotes\u002Freact\u002F08-interview\u002F12-scheduling-mechanism","详细聊聊 React 的调度机制",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":319,"title":320,"meta":321},"\u002Fnotes\u002Freact\u002F08-interview\u002F13-priority-and-lanes","聊聊 React 的优先级机制（Lane 模型）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":323,"title":324,"meta":325},"\u002Fnotes\u002Freact\u002F08-interview\u002F14-diff-algorithm","React 的 Diff 算法是什么样的",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":327,"title":328,"meta":329},"\u002Fnotes\u002Freact\u002F08-interview\u002F15-event-system","详细聊聊 React 的事件系统是如何实现的",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":331,"title":332,"meta":333},"\u002Fnotes\u002Freact\u002F08-interview\u002F16-portals-bubbling","React Portals 上的事件是否会冒泡到父组件，原理是什么",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":335,"title":336,"meta":337},"\u002Fnotes\u002Freact\u002F08-interview\u002F17-useEffect-impl","useEffect 的实现原理是什么",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":339,"title":340,"meta":341},"\u002Fnotes\u002Freact\u002F08-interview\u002F18-useContext-impl","请聊聊 useContext 的实现原理",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":343,"title":344,"meta":345},"\u002Fnotes\u002Freact\u002F09-react-18-in-practice\u002F01-automatic-batching-and-flushsync","React 18 自动批处理（Automatic Batching）与 flushSync",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":347,"title":348,"meta":349},"\u002Fnotes\u002Freact\u002F09-react-18-in-practice\u002F02-strictmode-and-idempotent-effects","React StrictMode：为什么会“双调用”？（源码\u002F机制视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":351,"title":352,"meta":353},"\u002Fnotes\u002Freact\u002F09-react-18-in-practice\u002F03-transition-useTransition-useDeferredValue","Transition：startTransition \u002F useTransition \u002F useDeferredValue（机制视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":355,"title":356,"meta":357},"\u002Fnotes\u002Freact\u002F09-react-18-in-practice\u002F04-suspense-loading-boundary-design","Suspense：加载态边界如何设计（机制\u002F架构视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":359,"title":360,"meta":361},"\u002Fnotes\u002Freact\u002F09-react-18-in-practice\u002F05-error-boundary-reporting-and-recovery","Error Boundary：兜底、重试与上报（自研 vs Sentry）（机制\u002F架构视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":363,"title":364,"meta":365},"\u002Fnotes\u002Freact\u002F09-react-18-in-practice","React 18 实战（并发特性与默认行为）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":367,"title":368,"meta":369},"\u002Fnotes\u002Freact\u002F10-routing-and-navigation\u002F01-routing-and-url-state-mental-model","路由与 URL State：统一心智模型（架构师视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":371,"title":372,"meta":373},"\u002Fnotes\u002Freact\u002F10-routing-and-navigation\u002F02-tanstack-router-route-tree-search-loader-prefetch","TanStack Router（Vite \u002F SPA）：Route Tree \u002F Search \u002F Loader \u002F Prefetch（落地篇）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":375,"title":376,"meta":377},"\u002Fnotes\u002Freact\u002F10-routing-and-navigation\u002F03-next-app-router-segments-layout-loading-error-not-found-prefetch","Next.js App Router：Segments \u002F Layouts \u002F Loading-Error-NotFound \u002F Prefetch（落地篇）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":379,"title":380,"meta":381},"\u002Fnotes\u002Freact\u002F10-routing-and-navigation","路由与导航（TanStack Router \u002F Next App Router）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":383,"title":384,"meta":385},"\u002Fnotes\u002Freact\u002F11-data-layer\u002F01-state-layering-ui-server-url-global","状态分层：UI \u002F Server \u002F URL \u002F Global（架构师视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":387,"title":388,"meta":389},"\u002Fnotes\u002Freact\u002F11-data-layer\u002F02-tanstack-query-caching-and-invalidation","TanStack Query：缓存模型与失效策略（Caching & Invalidation）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":391,"title":392,"meta":393},"\u002Fnotes\u002Freact\u002F11-data-layer\u002F03-optimistic-updates-and-consistency","TanStack Query：乐观更新与一致性（Optimistic Updates & Consistency）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":395,"title":396,"meta":397},"\u002Fnotes\u002Freact\u002F11-data-layer\u002F04-form-architecture-react-hook-form-validation-performance-testability","表单架构：React Hook Form 的受控\u002F非受控、校验、性能与可测试性（架构师视角）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":399,"title":400,"meta":401},"\u002Fnotes\u002Freact\u002F11-data-layer","数据层（Server State \u002F 表单 \u002F 状态分层）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":403,"title":404,"meta":405},"\u002Fnotes\u002Freact\u002F12-rendering-and-delivery\u002F01-hydration-mismatch","Hydration mismatch（React \u002F Next.js）：成因、检测、排查清单与工程化规避",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":407,"title":408,"meta":409},"\u002Fnotes\u002Freact\u002F12-rendering-and-delivery\u002F01-nextjs-cache-revalidate-consistency-online-not-updating","Next.js 缓存\u002F重验证与一致性：避免「线上怎么不更新」事故（App Router）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":411,"title":412,"meta":413},"\u002Fnotes\u002Freact\u002F12-rendering-and-delivery\u002F02-csr-ssr-ssg-isr-how-to-choose","CSR vs SSR vs SSG vs ISR：怎么选？边界是什么？（体验 + 成本 + 一致性）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":415,"title":416,"meta":417},"\u002Fnotes\u002Freact\u002F12-rendering-and-delivery\u002F04-streaming-ssr-with-suspense","Streaming SSR + Suspense：提升前端感知性能的利器",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":419,"title":420,"meta":421},"\u002Fnotes\u002Freact\u002F12-rendering-and-delivery","渲染与交付（CSR\u002FSSR\u002FStreaming\u002FHydration\u002F缓存）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":423,"title":424,"meta":425},"\u002Fnotes\u002Freact\u002F13-production-readiness\u002F01-observability-logging-metrics-tracing","前端可观测性体系：日志、指标与链路追踪",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":427,"title":428,"meta":429},"\u002Fnotes\u002Freact\u002F13-production-readiness\u002F02-auth-and-web-security","鉴权与 Web 安全：OAuth, JWT, XSS, CSRF, CSP",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":431,"title":432,"meta":433},"\u002Fnotes\u002Freact\u002F13-production-readiness","生产可用性（错误\u002F可观测\u002F鉴权\u002F安全）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":435,"title":436,"meta":437},"\u002Fnotes\u002Freact\u002F14-performance\u002F01-performance-playbook-and-metrics","前端性能定位 Playbook：从指标到归因",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":439,"title":440,"meta":441},"\u002Fnotes\u002Freact\u002F14-performance\u002F02-rendering-optimization-memo-context-virtualization","React 渲染性能优化：Memo, Context, 与虚拟化",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":443,"title":444,"meta":445},"\u002Fnotes\u002Freact\u002F14-performance\u002F03-asset-and-bundle-optimization","资源与 Bundle 优化：代码分割、图片与 CDN",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":447,"title":448,"meta":449},"\u002Fnotes\u002Freact\u002F14-performance","性能体系（定位 → 优化 → 度量）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":451,"title":452,"meta":453},"\u002Fnotes\u002Freact\u002F15-engineering-and-architecture\u002F01-component-system-and-design-system","组件体系与设计系统：构建规模化前端的基石",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":455,"title":456,"meta":457},"\u002Fnotes\u002Freact\u002F15-engineering-and-architecture\u002F02-testing-strategy-rtl-e2e-testability","前端测试体系：RTL, E2E 与可测性设计",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":459,"title":460,"meta":461},"\u002Fnotes\u002Freact\u002F15-engineering-and-architecture\u002F03-monorepo-and-dependency-management","Monorepo 与依赖治理：pnpm 和 Turborepo",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":463,"title":464,"meta":465},"\u002Fnotes\u002Freact\u002F15-engineering-and-architecture\u002F04-cicd-and-quality-gates","CI\u002FCD 与质量门禁：构建可靠的自动化流程",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":467,"title":468,"meta":469},"\u002Fnotes\u002Freact\u002F15-engineering-and-architecture\u002F05-bff-and-api-design","BFF 与 API 设计：前端架构师的视角",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":471,"title":472,"meta":473},"\u002Fnotes\u002Freact\u002F15-engineering-and-architecture","工程与架构治理（规模化）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":475,"title":476,"meta":477},"\u002Fnotes\u002Freact\u002F16-advanced\u002F01-rsc-and-server-actions-deep-dive","RSC\u002FServer Actions 深水区：边界、约束与缓存一致性",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":479,"title":480,"meta":481},"\u002Fnotes\u002Freact\u002F16-advanced\u002F02-micro-frontend-governance","微前端治理：样式、路由与通信",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":483,"title":484,"meta":485},"\u002Fnotes\u002Freact\u002F16-advanced\u002F03-realtime-and-offline","实时与离线：WebSocket, PWA 与 Service Worker",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":487,"title":488,"meta":489},"\u002Fnotes\u002Freact\u002F16-advanced\u002F04-a11y-i18n-compliance","a11y, i18n 与合规：构建负责任的全球化应用",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":491,"title":492,"meta":493},"\u002Fnotes\u002Freact\u002F16-advanced","进阶专题（按业务需要选做）",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"id":495,"type":496,"sourcePath":497,"routePath":415,"path":415,"title":416,"updatedAt":21,"meta":498,"body":500,"toc":1933},"bm90ZTpub3Rlcy9yZWFjdC8xMi1yZW5kZXJpbmctYW5kLWRlbGl2ZXJ5LzA0LXN0cmVhbWluZy1zc3Itd2l0aC1zdXNwZW5zZS5tZA","note","notes\u002Freact\u002F12-rendering-and-delivery\u002F04-streaming-ssr-with-suspense.md",{"id":495,"type":496,"sourcePath":497,"slug":499,"title":416,"updatedAt":21,"lastUpdated":21},"react\u002F12-rendering-and-delivery\u002F04-streaming-ssr-with-suspense",{"type":501,"children":502},"root",[503,511,527,531,538,543,548,555,702,708,884,887,893,922,940,973,989,992,998,1003,1009,1014,1083,1688,1694,1699,1763,1768,1771,1777,1782,1846,1849,1855,1927],{"type":504,"tag":505,"props":506,"children":508},"element","h1",{"id":507},"streaming-ssr-suspense提升前端感知性能的利器",[509],{"type":510,"value":416},"text",{"type":504,"tag":512,"props":513,"children":514},"blockquote",{},[515],{"type":504,"tag":516,"props":517,"children":518},"p",{},[519,525],{"type":504,"tag":520,"props":521,"children":522},"strong",{},[523],{"type":510,"value":524},"一句话结论",{"type":510,"value":526},"：Streaming SSR 结合 Suspense，允许服务器在数据准备就绪时，分块、流式地将 HTML 发送给客户端，客户端也能同步进行渐进式 Hydration，从而显著降低 TTFB 和 TTI，极大提升用户感知的页面加载性能。",{"type":504,"tag":528,"props":529,"children":530},"hr",{},[],{"type":504,"tag":532,"props":533,"children":535},"h2",{"id":534},"_1-机制拆解-how-it-works",[536],{"type":510,"value":537},"1. 机制拆解 (How it Works)",{"type":504,"tag":516,"props":539,"children":540},{},[541],{"type":510,"value":542},"传统的 SSR 是一个“瀑布模型”：服务器必须在获取完所有页面数据后，才开始渲染完整的 HTML，然后一次性发送给浏览器。如果某个数据请求缓慢，整个页面都会被阻塞。",{"type":504,"tag":516,"props":544,"children":545},{},[546],{"type":510,"value":547},"Streaming SSR 打破了这一模式，将渲染和传输过程变为“流水线作业”。",{"type":504,"tag":549,"props":550,"children":552},"h3",{"id":551},"核心机制两个流",[553],{"type":510,"value":554},"核心机制：两个“流”",{"type":504,"tag":556,"props":557,"children":558},"ol",{},[559,639],{"type":504,"tag":560,"props":561,"children":562},"li",{},[563,568,570],{"type":504,"tag":520,"props":564,"children":565},{},[566],{"type":510,"value":567},"服务器渲染流 (Server Rendering Stream)",{"type":510,"value":569},"：",{"type":504,"tag":571,"props":572,"children":573},"ul",{},[574,584,611,621],{"type":504,"tag":560,"props":575,"children":576},{},[577,582],{"type":504,"tag":520,"props":578,"children":579},{},[580],{"type":510,"value":581},"初始 Shell 发送",{"type":510,"value":583},"：服务器首先发送页面的“骨架” (Shell)，包含立即可用的 HTML 结构、CSS 和非 Suspense 包装的同步内容。这个 Shell 自身就是一个完整的 HTML 文档。",{"type":504,"tag":560,"props":585,"children":586},{},[587,592,594,601,603,609],{"type":504,"tag":520,"props":588,"children":589},{},[590],{"type":510,"value":591},"Fallback 占位",{"type":510,"value":593},"：对于被 ",{"type":504,"tag":595,"props":596,"children":598},"code",{"className":597},[],[599],{"type":510,"value":600},"\u003CSuspense>",{"type":510,"value":602}," 包裹的异步组件，服务器会在其位置渲染并发送 ",{"type":504,"tag":595,"props":604,"children":606},{"className":605},[],[607],{"type":510,"value":608},"fallback",{"type":510,"value":610}," UI（例如一个加载指示器）。",{"type":504,"tag":560,"props":612,"children":613},{},[614,619],{"type":504,"tag":520,"props":615,"children":616},{},[617],{"type":510,"value":618},"数据就绪，即刻推流",{"type":510,"value":620},"：一旦某个异步组件的数据在服务器上准备就绪（例如，API 请求完成），React 会立刻在服务器上渲染该组件，并通过同一个 HTTP 连接，将渲染好的 HTML 片段“推送”给客户端。",{"type":504,"tag":560,"props":622,"children":623},{},[624,629,631,637],{"type":504,"tag":520,"props":625,"children":626},{},[627],{"type":510,"value":628},"内联脚本注入",{"type":510,"value":630},"：推送的 HTML 片段旁边会附带一个 ",{"type":504,"tag":595,"props":632,"children":634},{"className":633},[],[635],{"type":510,"value":636},"\u003Cscript>",{"type":510,"value":638}," 标签，其中包含了用于将这段 HTML 插入到正确位置的 JavaScript 代码。",{"type":504,"tag":560,"props":640,"children":641},{},[642,647,648],{"type":504,"tag":520,"props":643,"children":644},{},[645],{"type":510,"value":646},"客户端 Hydration 流 (Client Hydration Stream)",{"type":510,"value":569},{"type":504,"tag":571,"props":649,"children":650},{},[651,661,685],{"type":504,"tag":560,"props":652,"children":653},{},[654,659],{"type":504,"tag":520,"props":655,"children":656},{},[657],{"type":510,"value":658},"同步 Hydration",{"type":510,"value":660},"：浏览器收到初始 Shell 后，会像传统 SSR 一样开始对可见部分进行 Hydration，使其具备交互性。",{"type":504,"tag":560,"props":662,"children":663},{},[664,669,671,676,678,683],{"type":504,"tag":520,"props":665,"children":666},{},[667],{"type":510,"value":668},"选择性 Hydration",{"type":510,"value":670},"：当新的 HTML 片段从服务器流式传输过来时，客户端 React 会利用附带的 ",{"type":504,"tag":595,"props":672,"children":674},{"className":673},[],[675],{"type":510,"value":636},{"type":510,"value":677}," 将其“填入”到 ",{"type":504,"tag":595,"props":679,"children":681},{"className":680},[],[682],{"type":510,"value":608},{"type":510,"value":684}," 所在的位置。",{"type":504,"tag":560,"props":686,"children":687},{},[688,693,695,700],{"type":504,"tag":520,"props":689,"children":690},{},[691],{"type":510,"value":692},"并发 Hydration",{"type":510,"value":694},"：重要的是，React 18 会",{"type":504,"tag":520,"props":696,"children":697},{},[698],{"type":510,"value":699},"优先 Hydrate 用户正在交互的区域",{"type":510,"value":701},"。例如，即使用户在页面其他部分还在加载时点击了某个按钮，React 也会优先处理该按钮所在组件的 Hydration，从而提供即时响应。这被称为“选择性 Hydration”。",{"type":504,"tag":549,"props":703,"children":705},{"id":704},"图解传统-ssr-vs-streaming-ssr",[706],{"type":510,"value":707},"图解：传统 SSR vs Streaming SSR",{"type":504,"tag":709,"props":710,"children":711},"table",{},[712,737],{"type":504,"tag":713,"props":714,"children":715},"thead",{},[716],{"type":504,"tag":717,"props":718,"children":719},"tr",{},[720,727,732],{"type":504,"tag":721,"props":722,"children":724},"th",{"align":723},"left",[725],{"type":510,"value":726},"阶段",{"type":504,"tag":721,"props":728,"children":729},{"align":723},[730],{"type":510,"value":731},"传统 SSR",{"type":504,"tag":721,"props":733,"children":734},{"align":723},[735],{"type":510,"value":736},"Streaming SSR with Suspense",{"type":504,"tag":738,"props":739,"children":740},"tbody",{},[741,763,787,803,824,840,856,870],{"type":504,"tag":717,"props":742,"children":743},{},[744,753,758],{"type":504,"tag":745,"props":746,"children":747},"td",{"align":723},[748],{"type":504,"tag":520,"props":749,"children":750},{},[751],{"type":510,"value":752},"服务器",{"type":504,"tag":745,"props":754,"children":755},{"align":723},[756],{"type":510,"value":757},"1. 等待所有数据",{"type":504,"tag":745,"props":759,"children":760},{"align":723},[761],{"type":510,"value":762},"1. 发送 HTML Shell + Suspense Fallback",{"type":504,"tag":717,"props":764,"children":765},{},[766,769,774],{"type":504,"tag":745,"props":767,"children":768},{"align":723},[],{"type":504,"tag":745,"props":770,"children":771},{"align":723},[772],{"type":510,"value":773},"2. 渲染完整 HTML",{"type":504,"tag":745,"props":775,"children":776},{"align":723},[777,779,785],{"type":510,"value":778},"2. (",{"type":504,"tag":595,"props":780,"children":782},{"className":781},[],[783],{"type":510,"value":784},"await Promise",{"type":510,"value":786},") 等待数据",{"type":504,"tag":717,"props":788,"children":789},{},[790,793,798],{"type":504,"tag":745,"props":791,"children":792},{"align":723},[],{"type":504,"tag":745,"props":794,"children":795},{"align":723},[796],{"type":510,"value":797},"3. 一次性发送",{"type":504,"tag":745,"props":799,"children":800},{"align":723},[801],{"type":510,"value":802},"3. 数据就绪后，渲染组件，推送到流",{"type":504,"tag":717,"props":804,"children":805},{},[806,814,819],{"type":504,"tag":745,"props":807,"children":808},{"align":723},[809],{"type":504,"tag":520,"props":810,"children":811},{},[812],{"type":510,"value":813},"客户端",{"type":504,"tag":745,"props":815,"children":816},{"align":723},[817],{"type":510,"value":818},"1. 下载完整 HTML",{"type":504,"tag":745,"props":820,"children":821},{"align":723},[822],{"type":510,"value":823},"1. 接收 Shell，渲染 Fallback",{"type":504,"tag":717,"props":825,"children":826},{},[827,830,835],{"type":504,"tag":745,"props":828,"children":829},{"align":723},[],{"type":504,"tag":745,"props":831,"children":832},{"align":723},[833],{"type":510,"value":834},"2. 下载所有 JS",{"type":504,"tag":745,"props":836,"children":837},{"align":723},[838],{"type":510,"value":839},"2. 下载主要 JS Bundle",{"type":504,"tag":717,"props":841,"children":842},{},[843,846,851],{"type":504,"tag":745,"props":844,"children":845},{"align":723},[],{"type":504,"tag":745,"props":847,"children":848},{"align":723},[849],{"type":510,"value":850},"3. Hydrate 整个页面",{"type":504,"tag":745,"props":852,"children":853},{"align":723},[854],{"type":510,"value":855},"3. Hydrate Shell 部分",{"type":504,"tag":717,"props":857,"children":858},{},[859,862,865],{"type":504,"tag":745,"props":860,"children":861},{"align":723},[],{"type":504,"tag":745,"props":863,"children":864},{"align":723},[],{"type":504,"tag":745,"props":866,"children":867},{"align":723},[868],{"type":510,"value":869},"4. 接收到 HTML 片段，替换 Fallback",{"type":504,"tag":717,"props":871,"children":872},{},[873,876,879],{"type":504,"tag":745,"props":874,"children":875},{"align":723},[],{"type":504,"tag":745,"props":877,"children":878},{"align":723},[],{"type":504,"tag":745,"props":880,"children":881},{"align":723},[882],{"type":510,"value":883},"5. Hydrate 新到的组件",{"type":504,"tag":528,"props":885,"children":886},{},[],{"type":504,"tag":532,"props":888,"children":890},{"id":889},"_2-常见误区追问-faq",[891],{"type":510,"value":892},"2. 常见误区\u002F追问 (FAQ)",{"type":504,"tag":516,"props":894,"children":895},{},[896,901,903,908,910,914,916,920],{"type":504,"tag":520,"props":897,"children":898},{},[899],{"type":510,"value":900},"Q1: Streaming SSR 和客户端渲染 (CSR) 的 Suspense 有何不同？",{"type":510,"value":902},"\nA: ",{"type":504,"tag":520,"props":904,"children":905},{},[906],{"type":510,"value":907},"目标不同",{"type":510,"value":909},"。CSR 的 Suspense 主要用于处理",{"type":504,"tag":520,"props":911,"children":912},{},[913],{"type":510,"value":813},{"type":510,"value":915},"的数据获取和代码分割时的加载状态。而 Streaming SSR 的 Suspense 则是为了让",{"type":504,"tag":520,"props":917,"children":918},{},[919],{"type":510,"value":752},{"type":510,"value":921},"能够“边获取数据边渲染”，将加载状态的等待从客户端提前到服务器，并通过流式传输隐藏网络延迟。",{"type":504,"tag":516,"props":923,"children":924},{},[925,930,932,938],{"type":504,"tag":520,"props":926,"children":927},{},[928],{"type":510,"value":929},"Q2: 如果我有多个 Suspense 边界，它们是并行加载的吗？",{"type":510,"value":931},"\nA: 是的。在服务器上，React 会 ",{"type":504,"tag":595,"props":933,"children":935},{"className":934},[],[936],{"type":510,"value":937},"Promise.all",{"type":510,"value":939}," 所有并行的数据请求。一旦任何一个请求完成，对应的 HTML 块就会被流式发送。这避免了请求串行化导致的阻塞。",{"type":504,"tag":516,"props":941,"children":942},{},[943,956,958,963,965,971],{"type":504,"tag":520,"props":944,"children":945},{},[946,948,954],{"type":510,"value":947},"Q3: 这是否意味着我不再需要 ",{"type":504,"tag":595,"props":949,"children":951},{"className":950},[],[952],{"type":510,"value":953},"useEffect",{"type":510,"value":955}," 来获取数据了？",{"type":510,"value":957},"\nA: 在全栈框架（如 Next.js）中，是的。数据获取的逻辑会从 ",{"type":504,"tag":595,"props":959,"children":961},{"className":960},[],[962],{"type":510,"value":953},{"type":510,"value":964}," “上移”到服务器组件或专门的数据加载函数中（如 Next.js 的 ",{"type":504,"tag":595,"props":966,"children":968},{"className":967},[],[969],{"type":510,"value":970},"loader",{"type":510,"value":972}," 或 React Server Components）。这使得数据获取与渲染更紧密地结合，是实现 Streaming SSR 的前提。",{"type":504,"tag":516,"props":974,"children":975},{},[976,981,982,987],{"type":504,"tag":520,"props":977,"children":978},{},[979],{"type":510,"value":980},"Q4: 对 SEO 有什么影响？",{"type":510,"value":902},{"type":504,"tag":520,"props":983,"children":984},{},[985],{"type":510,"value":986},"正面影响",{"type":510,"value":988},"。初始 Shell 包含了关键的同步内容，对 SEO 友好。随后流式传输的内容虽然对首次爬取可能不可见，但由于整体 TTFB 和 TTI 改善，搜索引擎可能会给予更高的性能评分。搜索引擎爬虫也在逐步进化以更好地支持这类流式渲染模式。",{"type":504,"tag":528,"props":990,"children":991},{},[],{"type":504,"tag":532,"props":993,"children":995},{"id":994},"_3-落地方案-implementation",[996],{"type":510,"value":997},"3. 落地方案 (Implementation)",{"type":504,"tag":516,"props":999,"children":1000},{},[1001],{"type":510,"value":1002},"直接在纯 React 中实现 Streaming SSR 相对复杂，需要手动配置服务器。因此，推荐的落地方案是使用支持此功能的现代全栈框架。",{"type":504,"tag":549,"props":1004,"children":1006},{"id":1005},"a-nextjs-app-router",[1007],{"type":510,"value":1008},"A. Next.js (App Router)",{"type":504,"tag":516,"props":1010,"children":1011},{},[1012],{"type":510,"value":1013},"Next.js App Router 是 Streaming SSR 的最佳实践范例。",{"type":504,"tag":571,"props":1015,"children":1016},{},[1017,1027,1058],{"type":504,"tag":560,"props":1018,"children":1019},{},[1020,1025],{"type":504,"tag":520,"props":1021,"children":1022},{},[1023],{"type":510,"value":1024},"默认启用",{"type":510,"value":1026},"：在 App Router 中，流式渲染是默认行为。",{"type":504,"tag":560,"props":1028,"children":1029},{},[1030,1041,1043,1048,1050,1056],{"type":504,"tag":520,"props":1031,"children":1032},{},[1033,1039],{"type":504,"tag":595,"props":1034,"children":1036},{"className":1035},[],[1037],{"type":510,"value":1038},"loading.js",{"type":510,"value":1040}," 文件",{"type":510,"value":1042},"：这是一个基于文件系统的约定。在任何目录下创建一个 ",{"type":504,"tag":595,"props":1044,"children":1046},{"className":1045},[],[1047],{"type":510,"value":1038},{"type":510,"value":1049}," 文件，它会自动成为该路由段落的 ",{"type":504,"tag":595,"props":1051,"children":1053},{"className":1052},[],[1054],{"type":510,"value":1055},"\u003CSuspense fallback={...}>",{"type":510,"value":1057},"。",{"type":504,"tag":560,"props":1059,"children":1060},{},[1061,1066,1068,1074,1076,1081],{"type":504,"tag":520,"props":1062,"children":1063},{},[1064],{"type":510,"value":1065},"数据获取",{"type":510,"value":1067},"：在页面组件或其子组件中直接使用 ",{"type":504,"tag":595,"props":1069,"children":1071},{"className":1070},[],[1072],{"type":510,"value":1073},"async\u002Fawait",{"type":510,"value":1075}," 获取数据。Next.js 会自动处理数据依赖，并在服务器上等待数据时，渲染 ",{"type":504,"tag":595,"props":1077,"children":1079},{"className":1078},[],[1080],{"type":510,"value":1038},{"type":510,"value":1082}," 作为 Fallback。",{"type":504,"tag":1084,"props":1085,"children":1090},"pre",{"className":1086,"code":1087,"language":1088,"meta":1089,"style":1089},"language-jsx shiki shiki-themes github-light github-dark","\u002F\u002F app\u002Fdashboard\u002Fpage.js\nimport { Suspense } from 'react';\nimport { UserProfile } from '.\u002FUserProfile';\nimport { TeamList } from '.\u002FTeamList';\nimport { StatsSkeleton, TeamSkeleton } from '.\u002FSkeletons';\n\nexport default function DashboardPage() {\n  return (\n    \u003Cdiv>\n      \u003Ch1>Dashboard\u003C\u002Fh1>\n      \u003CSuspense fallback={\u003CStatsSkeleton \u002F>}>\n        \u003CUserProfile \u002F>\n      \u003C\u002FsSuspense>\n      \u003CSuspense fallback={\u003CTeamSkeleton \u002F>}>\n        \u003CTeamList \u002F>\n      \u003C\u002FSuspense>\n    \u003C\u002Fdiv>\n  );\n}\n\n\u002F\u002F app\u002Fdashboard\u002FUserProfile.js\nasync function UserProfile() {\n  const user = await fetchUserData(); \u002F\u002F 模拟数据获取\n  return \u003Cdiv>{user.name}\u003C\u002Fdiv>;\n}\n\n\u002F\u002F app\u002Fdashboard\u002Floading.js (或者使用更细粒度的 Suspense)\nexport default function Loading() {\n  return \u003Cp>Loading dashboard...\u003C\u002Fp>;\n}\n","jsx","",[1091],{"type":504,"tag":595,"props":1092,"children":1093},{"__ignoreMap":1089},[1094,1106,1138,1164,1190,1216,1226,1256,1270,1290,1316,1355,1374,1392,1425,1442,1458,1475,1484,1493,1501,1510,1532,1571,1601,1609,1617,1626,1651,1680],{"type":504,"tag":1095,"props":1096,"children":1099},"span",{"class":1097,"line":1098},"line",1,[1100],{"type":504,"tag":1095,"props":1101,"children":1103},{"style":1102},"--shiki-default:#6A737D;--shiki-dark:#6A737D",[1104],{"type":510,"value":1105},"\u002F\u002F app\u002Fdashboard\u002Fpage.js\n",{"type":504,"tag":1095,"props":1107,"children":1109},{"class":1097,"line":1108},2,[1110,1116,1122,1127,1133],{"type":504,"tag":1095,"props":1111,"children":1113},{"style":1112},"--shiki-default:#D73A49;--shiki-dark:#F97583",[1114],{"type":510,"value":1115},"import",{"type":504,"tag":1095,"props":1117,"children":1119},{"style":1118},"--shiki-default:#24292E;--shiki-dark:#E1E4E8",[1120],{"type":510,"value":1121}," { Suspense } ",{"type":504,"tag":1095,"props":1123,"children":1124},{"style":1112},[1125],{"type":510,"value":1126},"from",{"type":504,"tag":1095,"props":1128,"children":1130},{"style":1129},"--shiki-default:#032F62;--shiki-dark:#9ECBFF",[1131],{"type":510,"value":1132}," 'react'",{"type":504,"tag":1095,"props":1134,"children":1135},{"style":1118},[1136],{"type":510,"value":1137},";\n",{"type":504,"tag":1095,"props":1139,"children":1141},{"class":1097,"line":1140},3,[1142,1146,1151,1155,1160],{"type":504,"tag":1095,"props":1143,"children":1144},{"style":1112},[1145],{"type":510,"value":1115},{"type":504,"tag":1095,"props":1147,"children":1148},{"style":1118},[1149],{"type":510,"value":1150}," { UserProfile } ",{"type":504,"tag":1095,"props":1152,"children":1153},{"style":1112},[1154],{"type":510,"value":1126},{"type":504,"tag":1095,"props":1156,"children":1157},{"style":1129},[1158],{"type":510,"value":1159}," '.\u002FUserProfile'",{"type":504,"tag":1095,"props":1161,"children":1162},{"style":1118},[1163],{"type":510,"value":1137},{"type":504,"tag":1095,"props":1165,"children":1167},{"class":1097,"line":1166},4,[1168,1172,1177,1181,1186],{"type":504,"tag":1095,"props":1169,"children":1170},{"style":1112},[1171],{"type":510,"value":1115},{"type":504,"tag":1095,"props":1173,"children":1174},{"style":1118},[1175],{"type":510,"value":1176}," { TeamList } ",{"type":504,"tag":1095,"props":1178,"children":1179},{"style":1112},[1180],{"type":510,"value":1126},{"type":504,"tag":1095,"props":1182,"children":1183},{"style":1129},[1184],{"type":510,"value":1185}," '.\u002FTeamList'",{"type":504,"tag":1095,"props":1187,"children":1188},{"style":1118},[1189],{"type":510,"value":1137},{"type":504,"tag":1095,"props":1191,"children":1193},{"class":1097,"line":1192},5,[1194,1198,1203,1207,1212],{"type":504,"tag":1095,"props":1195,"children":1196},{"style":1112},[1197],{"type":510,"value":1115},{"type":504,"tag":1095,"props":1199,"children":1200},{"style":1118},[1201],{"type":510,"value":1202}," { StatsSkeleton, TeamSkeleton } ",{"type":504,"tag":1095,"props":1204,"children":1205},{"style":1112},[1206],{"type":510,"value":1126},{"type":504,"tag":1095,"props":1208,"children":1209},{"style":1129},[1210],{"type":510,"value":1211}," '.\u002FSkeletons'",{"type":504,"tag":1095,"props":1213,"children":1214},{"style":1118},[1215],{"type":510,"value":1137},{"type":504,"tag":1095,"props":1217,"children":1219},{"class":1097,"line":1218},6,[1220],{"type":504,"tag":1095,"props":1221,"children":1223},{"emptyLinePlaceholder":1222},true,[1224],{"type":510,"value":1225},"\n",{"type":504,"tag":1095,"props":1227,"children":1229},{"class":1097,"line":1228},7,[1230,1235,1240,1245,1251],{"type":504,"tag":1095,"props":1231,"children":1232},{"style":1112},[1233],{"type":510,"value":1234},"export",{"type":504,"tag":1095,"props":1236,"children":1237},{"style":1112},[1238],{"type":510,"value":1239}," default",{"type":504,"tag":1095,"props":1241,"children":1242},{"style":1112},[1243],{"type":510,"value":1244}," function",{"type":504,"tag":1095,"props":1246,"children":1248},{"style":1247},"--shiki-default:#6F42C1;--shiki-dark:#B392F0",[1249],{"type":510,"value":1250}," DashboardPage",{"type":504,"tag":1095,"props":1252,"children":1253},{"style":1118},[1254],{"type":510,"value":1255},"() {\n",{"type":504,"tag":1095,"props":1257,"children":1259},{"class":1097,"line":1258},8,[1260,1265],{"type":504,"tag":1095,"props":1261,"children":1262},{"style":1112},[1263],{"type":510,"value":1264},"  return",{"type":504,"tag":1095,"props":1266,"children":1267},{"style":1118},[1268],{"type":510,"value":1269}," (\n",{"type":504,"tag":1095,"props":1271,"children":1273},{"class":1097,"line":1272},9,[1274,1279,1285],{"type":504,"tag":1095,"props":1275,"children":1276},{"style":1118},[1277],{"type":510,"value":1278},"    \u003C",{"type":504,"tag":1095,"props":1280,"children":1282},{"style":1281},"--shiki-default:#22863A;--shiki-dark:#85E89D",[1283],{"type":510,"value":1284},"div",{"type":504,"tag":1095,"props":1286,"children":1287},{"style":1118},[1288],{"type":510,"value":1289},">\n",{"type":504,"tag":1095,"props":1291,"children":1293},{"class":1097,"line":1292},10,[1294,1299,1303,1308,1312],{"type":504,"tag":1095,"props":1295,"children":1296},{"style":1118},[1297],{"type":510,"value":1298},"      \u003C",{"type":504,"tag":1095,"props":1300,"children":1301},{"style":1281},[1302],{"type":510,"value":505},{"type":504,"tag":1095,"props":1304,"children":1305},{"style":1118},[1306],{"type":510,"value":1307},">Dashboard\u003C\u002F",{"type":504,"tag":1095,"props":1309,"children":1310},{"style":1281},[1311],{"type":510,"value":505},{"type":504,"tag":1095,"props":1313,"children":1314},{"style":1118},[1315],{"type":510,"value":1289},{"type":504,"tag":1095,"props":1317,"children":1319},{"class":1097,"line":1318},11,[1320,1324,1330,1335,1340,1345,1350],{"type":504,"tag":1095,"props":1321,"children":1322},{"style":1118},[1323],{"type":510,"value":1298},{"type":504,"tag":1095,"props":1325,"children":1327},{"style":1326},"--shiki-default:#005CC5;--shiki-dark:#79B8FF",[1328],{"type":510,"value":1329},"Suspense",{"type":504,"tag":1095,"props":1331,"children":1332},{"style":1247},[1333],{"type":510,"value":1334}," fallback",{"type":504,"tag":1095,"props":1336,"children":1337},{"style":1112},[1338],{"type":510,"value":1339},"=",{"type":504,"tag":1095,"props":1341,"children":1342},{"style":1118},[1343],{"type":510,"value":1344},"{\u003C",{"type":504,"tag":1095,"props":1346,"children":1347},{"style":1326},[1348],{"type":510,"value":1349},"StatsSkeleton",{"type":504,"tag":1095,"props":1351,"children":1352},{"style":1118},[1353],{"type":510,"value":1354}," \u002F>}>\n",{"type":504,"tag":1095,"props":1356,"children":1358},{"class":1097,"line":1357},12,[1359,1364,1369],{"type":504,"tag":1095,"props":1360,"children":1361},{"style":1118},[1362],{"type":510,"value":1363},"        \u003C",{"type":504,"tag":1095,"props":1365,"children":1366},{"style":1326},[1367],{"type":510,"value":1368},"UserProfile",{"type":504,"tag":1095,"props":1370,"children":1371},{"style":1118},[1372],{"type":510,"value":1373}," \u002F>\n",{"type":504,"tag":1095,"props":1375,"children":1377},{"class":1097,"line":1376},13,[1378,1383,1388],{"type":504,"tag":1095,"props":1379,"children":1380},{"style":1118},[1381],{"type":510,"value":1382},"      \u003C\u002F",{"type":504,"tag":1095,"props":1384,"children":1385},{"style":1326},[1386],{"type":510,"value":1387},"sSuspense",{"type":504,"tag":1095,"props":1389,"children":1390},{"style":1118},[1391],{"type":510,"value":1289},{"type":504,"tag":1095,"props":1393,"children":1395},{"class":1097,"line":1394},14,[1396,1400,1404,1408,1412,1416,1421],{"type":504,"tag":1095,"props":1397,"children":1398},{"style":1118},[1399],{"type":510,"value":1298},{"type":504,"tag":1095,"props":1401,"children":1402},{"style":1326},[1403],{"type":510,"value":1329},{"type":504,"tag":1095,"props":1405,"children":1406},{"style":1247},[1407],{"type":510,"value":1334},{"type":504,"tag":1095,"props":1409,"children":1410},{"style":1112},[1411],{"type":510,"value":1339},{"type":504,"tag":1095,"props":1413,"children":1414},{"style":1118},[1415],{"type":510,"value":1344},{"type":504,"tag":1095,"props":1417,"children":1418},{"style":1326},[1419],{"type":510,"value":1420},"TeamSkeleton",{"type":504,"tag":1095,"props":1422,"children":1423},{"style":1118},[1424],{"type":510,"value":1354},{"type":504,"tag":1095,"props":1426,"children":1428},{"class":1097,"line":1427},15,[1429,1433,1438],{"type":504,"tag":1095,"props":1430,"children":1431},{"style":1118},[1432],{"type":510,"value":1363},{"type":504,"tag":1095,"props":1434,"children":1435},{"style":1326},[1436],{"type":510,"value":1437},"TeamList",{"type":504,"tag":1095,"props":1439,"children":1440},{"style":1118},[1441],{"type":510,"value":1373},{"type":504,"tag":1095,"props":1443,"children":1445},{"class":1097,"line":1444},16,[1446,1450,1454],{"type":504,"tag":1095,"props":1447,"children":1448},{"style":1118},[1449],{"type":510,"value":1382},{"type":504,"tag":1095,"props":1451,"children":1452},{"style":1326},[1453],{"type":510,"value":1329},{"type":504,"tag":1095,"props":1455,"children":1456},{"style":1118},[1457],{"type":510,"value":1289},{"type":504,"tag":1095,"props":1459,"children":1461},{"class":1097,"line":1460},17,[1462,1467,1471],{"type":504,"tag":1095,"props":1463,"children":1464},{"style":1118},[1465],{"type":510,"value":1466},"    \u003C\u002F",{"type":504,"tag":1095,"props":1468,"children":1469},{"style":1281},[1470],{"type":510,"value":1284},{"type":504,"tag":1095,"props":1472,"children":1473},{"style":1118},[1474],{"type":510,"value":1289},{"type":504,"tag":1095,"props":1476,"children":1478},{"class":1097,"line":1477},18,[1479],{"type":504,"tag":1095,"props":1480,"children":1481},{"style":1118},[1482],{"type":510,"value":1483},"  );\n",{"type":504,"tag":1095,"props":1485,"children":1487},{"class":1097,"line":1486},19,[1488],{"type":504,"tag":1095,"props":1489,"children":1490},{"style":1118},[1491],{"type":510,"value":1492},"}\n",{"type":504,"tag":1095,"props":1494,"children":1496},{"class":1097,"line":1495},20,[1497],{"type":504,"tag":1095,"props":1498,"children":1499},{"emptyLinePlaceholder":1222},[1500],{"type":510,"value":1225},{"type":504,"tag":1095,"props":1502,"children":1504},{"class":1097,"line":1503},21,[1505],{"type":504,"tag":1095,"props":1506,"children":1507},{"style":1102},[1508],{"type":510,"value":1509},"\u002F\u002F app\u002Fdashboard\u002FUserProfile.js\n",{"type":504,"tag":1095,"props":1511,"children":1513},{"class":1097,"line":1512},22,[1514,1519,1523,1528],{"type":504,"tag":1095,"props":1515,"children":1516},{"style":1112},[1517],{"type":510,"value":1518},"async",{"type":504,"tag":1095,"props":1520,"children":1521},{"style":1112},[1522],{"type":510,"value":1244},{"type":504,"tag":1095,"props":1524,"children":1525},{"style":1247},[1526],{"type":510,"value":1527}," UserProfile",{"type":504,"tag":1095,"props":1529,"children":1530},{"style":1118},[1531],{"type":510,"value":1255},{"type":504,"tag":1095,"props":1533,"children":1535},{"class":1097,"line":1534},23,[1536,1541,1546,1551,1556,1561,1566],{"type":504,"tag":1095,"props":1537,"children":1538},{"style":1112},[1539],{"type":510,"value":1540},"  const",{"type":504,"tag":1095,"props":1542,"children":1543},{"style":1326},[1544],{"type":510,"value":1545}," user",{"type":504,"tag":1095,"props":1547,"children":1548},{"style":1112},[1549],{"type":510,"value":1550}," =",{"type":504,"tag":1095,"props":1552,"children":1553},{"style":1112},[1554],{"type":510,"value":1555}," await",{"type":504,"tag":1095,"props":1557,"children":1558},{"style":1247},[1559],{"type":510,"value":1560}," fetchUserData",{"type":504,"tag":1095,"props":1562,"children":1563},{"style":1118},[1564],{"type":510,"value":1565},"(); ",{"type":504,"tag":1095,"props":1567,"children":1568},{"style":1102},[1569],{"type":510,"value":1570},"\u002F\u002F 模拟数据获取\n",{"type":504,"tag":1095,"props":1572,"children":1573},{"class":1097,"line":5},[1574,1578,1583,1587,1592,1596],{"type":504,"tag":1095,"props":1575,"children":1576},{"style":1112},[1577],{"type":510,"value":1264},{"type":504,"tag":1095,"props":1579,"children":1580},{"style":1118},[1581],{"type":510,"value":1582}," \u003C",{"type":504,"tag":1095,"props":1584,"children":1585},{"style":1281},[1586],{"type":510,"value":1284},{"type":504,"tag":1095,"props":1588,"children":1589},{"style":1118},[1590],{"type":510,"value":1591},">{user.name}\u003C\u002F",{"type":504,"tag":1095,"props":1593,"children":1594},{"style":1281},[1595],{"type":510,"value":1284},{"type":504,"tag":1095,"props":1597,"children":1598},{"style":1118},[1599],{"type":510,"value":1600},">;\n",{"type":504,"tag":1095,"props":1602,"children":1604},{"class":1097,"line":1603},25,[1605],{"type":504,"tag":1095,"props":1606,"children":1607},{"style":1118},[1608],{"type":510,"value":1492},{"type":504,"tag":1095,"props":1610,"children":1612},{"class":1097,"line":1611},26,[1613],{"type":504,"tag":1095,"props":1614,"children":1615},{"emptyLinePlaceholder":1222},[1616],{"type":510,"value":1225},{"type":504,"tag":1095,"props":1618,"children":1620},{"class":1097,"line":1619},27,[1621],{"type":504,"tag":1095,"props":1622,"children":1623},{"style":1102},[1624],{"type":510,"value":1625},"\u002F\u002F app\u002Fdashboard\u002Floading.js (或者使用更细粒度的 Suspense)\n",{"type":504,"tag":1095,"props":1627,"children":1629},{"class":1097,"line":1628},28,[1630,1634,1638,1642,1647],{"type":504,"tag":1095,"props":1631,"children":1632},{"style":1112},[1633],{"type":510,"value":1234},{"type":504,"tag":1095,"props":1635,"children":1636},{"style":1112},[1637],{"type":510,"value":1239},{"type":504,"tag":1095,"props":1639,"children":1640},{"style":1112},[1641],{"type":510,"value":1244},{"type":504,"tag":1095,"props":1643,"children":1644},{"style":1247},[1645],{"type":510,"value":1646}," Loading",{"type":504,"tag":1095,"props":1648,"children":1649},{"style":1118},[1650],{"type":510,"value":1255},{"type":504,"tag":1095,"props":1652,"children":1654},{"class":1097,"line":1653},29,[1655,1659,1663,1667,1672,1676],{"type":504,"tag":1095,"props":1656,"children":1657},{"style":1112},[1658],{"type":510,"value":1264},{"type":504,"tag":1095,"props":1660,"children":1661},{"style":1118},[1662],{"type":510,"value":1582},{"type":504,"tag":1095,"props":1664,"children":1665},{"style":1281},[1666],{"type":510,"value":516},{"type":504,"tag":1095,"props":1668,"children":1669},{"style":1118},[1670],{"type":510,"value":1671},">Loading dashboard...\u003C\u002F",{"type":504,"tag":1095,"props":1673,"children":1674},{"style":1281},[1675],{"type":510,"value":516},{"type":504,"tag":1095,"props":1677,"children":1678},{"style":1118},[1679],{"type":510,"value":1600},{"type":504,"tag":1095,"props":1681,"children":1683},{"class":1097,"line":1682},30,[1684],{"type":504,"tag":1095,"props":1685,"children":1686},{"style":1118},[1687],{"type":510,"value":1492},{"type":504,"tag":549,"props":1689,"children":1691},{"id":1690},"b-tanstack-router-vite-手动配置",[1692],{"type":510,"value":1693},"B. TanStack Router + Vite (手动配置)",{"type":504,"tag":516,"props":1695,"children":1696},{},[1697],{"type":510,"value":1698},"虽然 TanStack Router 主要关注客户端，但结合 Vite 的 SSR API，也可以手动实现流式渲染。这需要更多的底层配置。",{"type":504,"tag":556,"props":1700,"children":1701},{},[1702,1728,1746],{"type":504,"tag":560,"props":1703,"children":1704},{},[1705,1718,1720,1726],{"type":504,"tag":520,"props":1706,"children":1707},{},[1708,1710,1716],{"type":510,"value":1709},"服务器入口 (",{"type":504,"tag":595,"props":1711,"children":1713},{"className":1712},[],[1714],{"type":510,"value":1715},"entry-server.jsx",{"type":510,"value":1717},")",{"type":510,"value":1719},"：使用 React 的 ",{"type":504,"tag":595,"props":1721,"children":1723},{"className":1722},[],[1724],{"type":510,"value":1725},"renderToPipeableStream",{"type":510,"value":1727}," API。",{"type":504,"tag":560,"props":1729,"children":1730},{},[1731,1736,1738,1744],{"type":504,"tag":520,"props":1732,"children":1733},{},[1734],{"type":510,"value":1735},"配置 Express\u002FNode.js 服务器",{"type":510,"value":1737},"：创建一个服务器，导入 Vite 编译后的服务器入口，并将其输出 ",{"type":504,"tag":595,"props":1739,"children":1741},{"className":1740},[],[1742],{"type":510,"value":1743},"pipe",{"type":510,"value":1745}," 到 HTTP 响应流中。",{"type":504,"tag":560,"props":1747,"children":1748},{},[1749,1754,1756,1761],{"type":504,"tag":520,"props":1750,"children":1751},{},[1752],{"type":510,"value":1753},"数据加载",{"type":510,"value":1755},"：利用 TanStack Router 的 ",{"type":504,"tag":595,"props":1757,"children":1759},{"className":1758},[],[1760],{"type":510,"value":970},{"type":510,"value":1762}," 函数进行服务器端数据获取，并将数据传递给组件。",{"type":504,"tag":516,"props":1764,"children":1765},{},[1766],{"type":510,"value":1767},"这套方案更灵活，但对工程能力要求更高。",{"type":504,"tag":528,"props":1769,"children":1770},{},[],{"type":504,"tag":532,"props":1772,"children":1774},{"id":1773},"_4-观测与验证-observability",[1775],{"type":510,"value":1776},"4. 观测与验证 (Observability)",{"type":504,"tag":516,"props":1778,"children":1779},{},[1780],{"type":510,"value":1781},"如何确认 Streaming SSR 正在按预期工作？",{"type":504,"tag":556,"props":1783,"children":1784},{},[1785,1807,1829],{"type":504,"tag":560,"props":1786,"children":1787},{},[1788,1793,1794],{"type":504,"tag":520,"props":1789,"children":1790},{},[1791],{"type":510,"value":1792},"浏览器网络面板 (Network Panel)",{"type":510,"value":569},{"type":504,"tag":571,"props":1795,"children":1796},{},[1797,1802],{"type":504,"tag":560,"props":1798,"children":1799},{},[1800],{"type":510,"value":1801},"检查主文档请求的 Timing 选项卡。你会看到一个很长的“Content Download”时间，这正是流式传输的特征。",{"type":504,"tag":560,"props":1803,"children":1804},{},[1805],{"type":510,"value":1806},"在 Response 选项卡中，你会看到 HTML 并不是一次性加载完成，而是分块到达。",{"type":504,"tag":560,"props":1808,"children":1809},{},[1810,1815,1816],{"type":504,"tag":520,"props":1811,"children":1812},{},[1813],{"type":510,"value":1814},"WebPageTest 或 Lighthouse",{"type":510,"value":569},{"type":504,"tag":571,"props":1817,"children":1818},{},[1819,1824],{"type":504,"tag":560,"props":1820,"children":1821},{},[1822],{"type":510,"value":1823},"观察“First Paint”和“Time to First Byte (TTFB)”指标。由于 Shell 的快速发送，这些指标会非常理想。",{"type":504,"tag":560,"props":1825,"children":1826},{},[1827],{"type":510,"value":1828},"对比“Time to Interactive (TTI)”，它也应该比传统 SSR 更快，因为 Hydration 是渐进式的。",{"type":504,"tag":560,"props":1830,"children":1831},{},[1832,1837,1838],{"type":504,"tag":520,"props":1833,"children":1834},{},[1835],{"type":510,"value":1836},"禁用 JavaScript 验证",{"type":510,"value":569},{"type":504,"tag":571,"props":1839,"children":1840},{},[1841],{"type":504,"tag":560,"props":1842,"children":1843},{},[1844],{"type":510,"value":1845},"在浏览器中禁用 JavaScript 并重新加载页面。你应该能看到 Fallback UI（例如骨架屏）。这证明了服务器正确地发送了初始的占位符。",{"type":504,"tag":528,"props":1847,"children":1848},{},[],{"type":504,"tag":532,"props":1850,"children":1852},{"id":1851},"_5-关联阅读",[1853],{"type":510,"value":1854},"5. 关联阅读",{"type":504,"tag":571,"props":1856,"children":1857},{},[1858,1877,1893,1911],{"type":504,"tag":560,"props":1859,"children":1860},{},[1861,1866,1868],{"type":504,"tag":520,"props":1862,"children":1863},{},[1864],{"type":510,"value":1865},"React 18 官方公告",{"type":510,"value":1867},": ",{"type":504,"tag":1869,"props":1870,"children":1874},"a",{"href":1871,"rel":1872},"https:\u002F\u002Fgithub.com\u002Freactwg\u002Freact-18\u002Fdiscussions\u002F37",[1873],"nofollow",[1875],{"type":510,"value":1876},"New Suspense SSR Architecture in React 18",{"type":504,"tag":560,"props":1878,"children":1879},{},[1880,1885,1886],{"type":504,"tag":520,"props":1881,"children":1882},{},[1883],{"type":510,"value":1884},"Next.js 文档",{"type":510,"value":1867},{"type":504,"tag":1869,"props":1887,"children":1890},{"href":1888,"rel":1889},"https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fapp\u002Fbuilding-your-application\u002Frouting\u002Floading-ui-and-streaming",[1873],[1891],{"type":510,"value":1892},"Streaming and Suspense",{"type":504,"tag":560,"props":1894,"children":1895},{},[1896,1901,1903,1909],{"type":504,"tag":520,"props":1897,"children":1898},{},[1899],{"type":510,"value":1900},"Hydration Mismatch 排查",{"type":510,"value":1902},": (指向 ",{"type":504,"tag":595,"props":1904,"children":1906},{"className":1905},[],[1907],{"type":510,"value":1908},"notes\u002F12\u002F01-hydration-mismatch.md",{"type":510,"value":1910}," 的链接)",{"type":504,"tag":560,"props":1912,"children":1913},{},[1914,1919,1920,1926],{"type":504,"tag":520,"props":1915,"children":1916},{},[1917],{"type":510,"value":1918},"Suspense 加载态边界设计",{"type":510,"value":1902},{"type":504,"tag":595,"props":1921,"children":1923},{"className":1922},[],[1924],{"type":510,"value":1925},"notes\u002F09\u002F04-suspense-loading-boundary-design.md",{"type":510,"value":1910},{"type":504,"tag":1928,"props":1929,"children":1930},"style",{},[1931],{"type":510,"value":1932},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":1089,"searchDepth":1108,"depth":1108,"links":1934},[1935,1939,1940,1944,1945],{"id":534,"depth":1108,"text":537,"children":1936},[1937,1938],{"id":551,"depth":1140,"text":554},{"id":704,"depth":1140,"text":707},{"id":889,"depth":1108,"text":892},{"id":994,"depth":1108,"text":997,"children":1941},[1942,1943],{"id":1005,"depth":1140,"text":1008},{"id":1690,"depth":1140,"text":1693},{"id":1773,"depth":1108,"text":1776},{"id":1851,"depth":1108,"text":1854},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1947},"\u003Cpath fill=\"currentColor\" d=\"m10.828 12l4.95 4.95l-1.414 1.415L8 12l6.364-6.364l1.414 1.414z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1949},"\u003Cpath fill=\"currentColor\" d=\"M3 4h18v2H3zm0 7h12v2H3zm0 7h18v2H3z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":1951},"\u003Cpath fill=\"currentColor\" d=\"m13.172 12l-4.95-4.95l1.414-1.413L16 12l-6.364 6.364l-1.414-1.415z\"\u002F>",{"left":4,"top":4,"width":1953,"height":1953,"rotate":4,"vFlip":6,"hFlip":6,"body":1954},1024,"\u003Cpath fill=\"currentColor\" d=\"M768 832a128 128 0 0 1-128 128H192A128 128 0 0 1 64 832V384a128 128 0 0 1 128-128v64a64 64 0 0 0-64 64v448a64 64 0 0 0 64 64h448a64 64 0 0 0 64-64z\"\u002F>\u003Cpath fill=\"currentColor\" d=\"M384 128a64 64 0 0 0-64 64v448a64 64 0 0 0 64 64h448a64 64 0 0 0 64-64V192a64 64 0 0 0-64-64zm0-64h448a128 128 0 0 1 128 128v448a128 128 0 0 1-128 128H384a128 128 0 0 1-128-128V192A128 128 0 0 1 384 64\"\u002F>"]