回復(fù)流式渲染提速:前端性能優(yōu)化的關(guān)鍵路徑)
Claude 這次在網(wǎng)頁(yè)端和桌面端做了一件看起來(lái)不大、實(shí)際很關(guān)鍵的事把長(zhǎng)回復(fù)的流式渲染速度提升了大約 4 倍。這里的“提速”不在模型側(cè)而在前端渲染側(cè)。模型生成的 token 數(shù)量沒(méi)有變變快的是頁(yè)面把 token 流變成可讀文本、Markdown、代碼塊、可滾動(dòng)長(zhǎng)文這一整條處理鏈路。長(zhǎng)回復(fù)是 LLM 產(chǎn)品里最容易暴露體驗(yàn)短板的地方。寫(xiě)長(zhǎng)文、生成完整代碼、做長(zhǎng)文檔對(duì)話時(shí)如果渲染線程跟不上 token 到達(dá)速度就會(huì)出現(xiàn)“字已經(jīng)輸出完了但頁(yè)面還要卡幾秒才能滾動(dòng)”“輸入框打字掉幀”“代碼塊高亮出得很慢”這類(lèi)現(xiàn)象。Claude 這次優(yōu)化的目標(biāo)就是把這些卡頓壓下去。這篇文章會(huì)做三件事先拆解長(zhǎng)回復(fù)流式渲染的性能瓶頸到底在哪再給一條可落地的前端流式渲染優(yōu)化路徑包含增量解析、任務(wù)切片、Web Worker 處理和 fetch 流式讀取示例最后給出一套不依賴 Claude 內(nèi)部實(shí)現(xiàn)的性能驗(yàn)證方法你可以直接用在手頭的 AI 產(chǎn)品上。適合閱讀的讀者正在寫(xiě) AI Chat 產(chǎn)品的前端工程師、負(fù)責(zé) LLM 應(yīng)用性能優(yōu)化的開(kāi)發(fā)者以及想搞清楚“流式渲染提速”到底在優(yōu)化什么的技術(shù)負(fù)責(zé)人。1. 核心能力速覽先說(shuō)清楚一個(gè)前提Claude 網(wǎng)頁(yè)端與桌面端長(zhǎng)回復(fù)流式渲染提速 4 倍這個(gè)口徑來(lái)自外部公開(kāi)信息。官方?jīng)]有放出足夠詳細(xì)的基準(zhǔn)測(cè)試原始數(shù)據(jù)所以本文不會(huì)聲稱“復(fù)現(xiàn)了 4 倍提升”而是把這個(gè)事件當(dāng)作引子重點(diǎn)講流式渲染優(yōu)化的通用工程方法。具體能提升多少必須在自己的項(xiàng)目里做前后對(duì)比。能力項(xiàng)說(shuō)明優(yōu)化產(chǎn)品Claude 網(wǎng)頁(yè)端、桌面客戶端優(yōu)化場(chǎng)景長(zhǎng)回復(fù)、長(zhǎng)文本輸出的流式渲染優(yōu)化方向前端渲染鏈路不是模型推理速度提升幅度官方口徑約 4 倍具體以實(shí)際測(cè)試為準(zhǔn)常見(jiàn)技術(shù)方向token 增量處理、Markdown 流式解析、渲染任務(wù)調(diào)度可復(fù)用范圍所有帶 LLM 流式輸出的 Web 應(yīng)用、桌面端應(yīng)用驗(yàn)證方式模擬流式接口 Chrome DevTools Performance主要收益減少滾動(dòng)卡頓、降低主線程占用、提升打字響應(yīng)結(jié)論放在前面這類(lèi)優(yōu)化的核心不是“把模型輸出變快”而是“讓頁(yè)面在輸出過(guò)程中不卡”。下面按瓶頸、優(yōu)化路徑、驗(yàn)證方法展開(kāi)。2. 長(zhǎng)回復(fù)流式渲染為什么會(huì)卡頓2.1 渲染速度跟不上 token 到達(dá)速度大模型流式輸出的速度并不慢。一個(gè)正常的大模型接口平均每秒能返回幾十到上百個(gè) token。放到界面上這就是每秒幾十次網(wǎng)絡(luò)回調(diào)。如果前端每收到一個(gè) chunk 就立刻做一次完整 DOM 更新渲染任務(wù)就會(huì)以每秒鐘二三十次的頻率壓到主線程上??D的根本原因是節(jié)奏不匹配網(wǎng)絡(luò)層是高頻小包渲染層是低吞吐大任務(wù)。每次更新如果還要觸發(fā) Markdown 重解析、代碼高亮、布局計(jì)算主線程很快就會(huì)被占滿。2.2 全量重解析是最大消耗很多 AI 聊天頁(yè)面最初實(shí)現(xiàn)時(shí)是把已收到的全部文本當(dāng)作一個(gè)整體字符串每次有新的 token 到達(dá)就用這個(gè)字符串重新走一遍 Markdown 解析和 HTML 渲染。文本短的時(shí)候問(wèn)題不大一旦累計(jì)到幾千字、幾萬(wàn)字每次重解析的成本會(huì)跟著全文長(zhǎng)度一起上漲。這種實(shí)現(xiàn)的復(fù)雜度是 O(n)n 是當(dāng)前已生成的文本長(zhǎng)度。token 越多每次更新越慢到長(zhǎng)回復(fù)后期單次解析可能就要幾百毫秒。用戶感知就是生成到一半頁(yè)面越來(lái)越卡。2.3 高頻 DOM 更新占滿主線程LLM 聊天界面里常見(jiàn)的 DOM 更新動(dòng)作包括替換正文容器、更新代碼高亮、調(diào)整滾動(dòng)位置、更新 token 計(jì)數(shù)。這些動(dòng)作如果高頻觸發(fā)會(huì)在 Performance 面板里形成一連串 Long Task。瀏覽器主線程被這些任務(wù)占據(jù)后輸入框的 keydown 事件排隊(duì)等待用戶打字就會(huì)出現(xiàn)明顯延遲。長(zhǎng)回復(fù)場(chǎng)景里還有一個(gè)隱藏問(wèn)題全文一直掛在 DOM 上沒(méi)有分頁(yè)或虛擬滾動(dòng)。當(dāng)頁(yè)面節(jié)點(diǎn)數(shù)量從幾百漲到幾千、幾萬(wàn)瀏覽器在樣式重算和重繪上的時(shí)間會(huì)顯著增加。2.4 長(zhǎng)文本滾動(dòng)區(qū)域破壞滾動(dòng)手勢(shì)用戶看長(zhǎng)回復(fù)時(shí)通常希望邊生成邊往上讀同時(shí)又能隨時(shí)拖動(dòng)滾動(dòng)條。如果每次新 token 到達(dá)都強(qiáng)制滾動(dòng)到底部會(huì)打斷用戶的閱讀節(jié)奏如果完全不滾動(dòng)用戶又看不到最新內(nèi)容。這種“滾動(dòng)策略”處理不好體驗(yàn)上比渲染性能問(wèn)題更明顯。更隱蔽的是布局抖動(dòng)。每次新內(nèi)容插入到滾動(dòng)容器頂部或底部瀏覽器都要重新計(jì)算滾動(dòng)高度一旦插入位置和滾動(dòng)位置互相影響就可能出現(xiàn)滾動(dòng)條跳變。3. 提速 4 倍的常見(jiàn)技術(shù)路徑下面這些優(yōu)化路徑是流式渲染場(chǎng)景下通用的工程做法。Claude 的具體實(shí)現(xiàn)細(xì)節(jié)沒(méi)有公開(kāi)但同類(lèi)產(chǎn)品要在這里提效通常會(huì)沿著這幾個(gè)方向做。3.1 全量重渲染改為增量渲染核心改動(dòng)是維護(hù)一個(gè)“已經(jīng)渲染到哪了”的游標(biāo)。每次收到新 chunk只處理新增部分而不是把整個(gè)歷史文本重新解析一遍。已渲染的歷史內(nèi)容保持不動(dòng)新內(nèi)容追加到容器尾部。這樣單次更新時(shí)間不隨全文長(zhǎng)度增長(zhǎng)整體復(fù)雜度從 O(n) 降為 O(增量)。3.2 把穩(wěn)定內(nèi)容和實(shí)時(shí)內(nèi)容分開(kāi)管理長(zhǎng)回復(fù)里Markdown 段落一旦閉合就不會(huì)再變化。代碼塊、列表、標(biāo)題都屬于穩(wěn)定結(jié)構(gòu)。可以先把這些穩(wěn)定內(nèi)容渲染成正式 DOM 節(jié)點(diǎn)中間的臨時(shí) token 流放到一個(gè)輕量的“游標(biāo)區(qū)間”里。等到游標(biāo)區(qū)間積累到成段內(nèi)容再提升為正式節(jié)點(diǎn)。這樣避免了每來(lái)一個(gè) token 都操作整棵 DOM 樹(shù)。3.3 代碼塊和列表專項(xiàng)渲染代碼塊是長(zhǎng)回復(fù)里最重的渲染對(duì)象。一次生成幾百行代碼時(shí)語(yǔ)法高亮可能比 Token 流本身更耗時(shí)。常見(jiàn)做法是代碼渲染先降級(jí)為普通文本展示高亮任務(wù)通過(guò)異步分片或 Worker 完成。列表和表格同理不急著實(shí)時(shí)渲染復(fù)雜樣式先保證文本可見(jiàn)。3.4 請(qǐng)求調(diào)度而不是每包必渲染網(wǎng)絡(luò)回調(diào)和渲染任務(wù)不必一一對(duì)應(yīng)??梢韵劝盐谋緦?xiě)入緩沖區(qū)再通過(guò) requestAnimationFrame 或 requestIdleCallback 統(tǒng)一提交。比如每 50 到 100 毫秒刷新一次界面把期間累積的增量一次渲染。犧牲一點(diǎn)“逐字輸出”的觀感換來(lái)主線程空閑和滾動(dòng)流暢。3.5 Web 端與桌面端共用渲染核心桌面端通常基于 WebView 或 Electron渲染核心如果能和 Web 端復(fù)用同一套邏輯維護(hù)成本會(huì)低很多。優(yōu)化一次兩端同時(shí)生效。這也是 Claude 網(wǎng)頁(yè)和桌面端能同步提速的原因之一。4. 環(huán)境準(zhǔn)備與流式渲染驗(yàn)證方案要驗(yàn)證流式渲染性能不一定要接真實(shí)大模型。準(zhǔn)備一個(gè)能模擬長(zhǎng)回復(fù)輸出的流式接口再配合瀏覽器性能工具就能完成大部分實(shí)驗(yàn)。4.1 準(zhǔn)備一個(gè)可控的流式輸出源推薦使用 FastAPI 或 Node.js 啟動(dòng)一個(gè)本地服務(wù)用 SSE 格式按固定間隔推送文本。這樣能控制 token 的到達(dá)速度方便前后對(duì)比。# requirements: fastapi uvicorn from fastapi import FastAPI from fastapi.responses import StreamingResponse import asyncio app FastAPI() async def generate(): chunk 這是用于測(cè)試流式渲染性能的長(zhǎng)文本內(nèi)容。 for i in range(200): yield fdata: {chunk} 第{i 1}段\n\n await asyncio.sleep(0.05) app.post(/api/stream) async def stream(): return StreamingResponse(generate(), media_typetext/event-stream)啟動(dòng)命令uvicorn main:app --host 127.0.0.1 --port 80004.2 確定核心指標(biāo)驗(yàn)證流式渲染性能建議先固定幾項(xiàng)指標(biāo)指標(biāo)名稱定義觀察方式TTFT從發(fā)起請(qǐng)求到第一段內(nèi)容可見(jiàn)DevTools Network字符渲染速率每秒實(shí)際出現(xiàn)在屏幕上的字符數(shù)視頻錄制或腳本統(tǒng)計(jì)長(zhǎng)任務(wù)耗時(shí)主線程上超過(guò) 50ms 的任務(wù)Performance 面板交互延遲輸入框敲字到字符出現(xiàn)的時(shí)間Input 事件分析滾動(dòng)幀率滾動(dòng)長(zhǎng)文本時(shí)的 FPSPerformance 面板 FPS 圖4.3 用 DevTools Performance 記錄現(xiàn)場(chǎng)打開(kāi) Chrome DevTools切到 Performance 面板點(diǎn)擊錄制然后在頁(yè)面上發(fā)起一次長(zhǎng)回復(fù)生成。等輸出結(jié)束后停止錄制重點(diǎn)看 Long Task、Recalculate Style 和 Layout 三條記錄。如果 Long Task 出現(xiàn)在每次網(wǎng)絡(luò)回調(diào)之后說(shuō)明當(dāng)前渲染實(shí)現(xiàn)確實(shí)在和 token 流搶主線程。這個(gè)現(xiàn)場(chǎng)記錄就是優(yōu)化的基線數(shù)據(jù)。5. 流式渲染優(yōu)化落地示例下面給三組代碼。第一組是常見(jiàn)但性能較差的基線條案第二組改成游標(biāo)增量更新第三組把 Markdown 解析放到 Worker 中。它們不是完整生產(chǎn)實(shí)現(xiàn)但能直接跑通并體現(xiàn)優(yōu)化思路。5.1 基線版本每個(gè) chunk 都全量更新// 基線版本每收到一個(gè) chunk 就全量替換 innerHTML const container document.getElementById(output); const response await fetch(/api/stream, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ prompt: 寫(xiě)一篇長(zhǎng)文 }) }); const reader response.body.getReader(); const decoder new TextDecoder(); while (true) { const { done, value } await reader.read(); if (done) break; const text decoder.decode(value, { stream: true }); container.innerHTML text; // 每次全量重解析長(zhǎng)文后越來(lái)越卡 }這個(gè)版本的問(wèn)題很直觀每次網(wǎng)絡(luò)包到達(dá)都會(huì)走一次全量解析和 DOM 替換。文本從 1000 字漲到 10000 字時(shí)單次處理時(shí)間會(huì)顯著上升。5.2 改進(jìn)版本游標(biāo)增量提交const container document.getElementById(output); let fullText ; let renderedLength 0; function flushIncremental() { const newText fullText.slice(renderedLength); if (!newText) return; // 先把純文本放進(jìn)去避免每次解析 Markdown const span document.createElement(span); span.textContent newText; container.appendChild(span); renderedLength fullText.length; } const response await fetch(/api/stream, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ prompt: 寫(xiě)一篇長(zhǎng)文 }) }); const reader response.body.getReader(); const decoder new TextDecoder(); while (true) { const { done, value } await reader.read(); if (done) break; fullText decoder.decode(value, { stream: true }); // 使用 requestIdleCallback 降低渲染優(yōu)先級(jí) if (typeof requestIdleCallback function) { requestIdleCallback(flushIncremental, { timeout: 200 }); } else { setTimeout(flushIncremental, 50); } }這個(gè)版本把“全量替換”改成了“只追加新增部分”同時(shí)通過(guò) requestIdleCallback 合并渲染任務(wù)避免每個(gè)網(wǎng)絡(luò)包都強(qiáng)制觸發(fā)一次布局。5.3 進(jìn)一步改進(jìn)在 Web Worker 里解析 Markdown主線程只負(fù)責(zé) DOM 提交把 Markdown 解析這種計(jì)算型工作交給 Worker。// markdown.worker.js // 這里用簡(jiǎn)化邏輯演示實(shí)際項(xiàng)目可換成 markdown-it 或 marked self.onmessage (event) { const { fullText, renderedLength } event.data; const newText fullText.slice(renderedLength); // 模擬 Markdown 解析只把換行轉(zhuǎn)成 p 塊 const html newText .split(\n\n) .map((block) p${block}/p) .join(); self.postMessage({ html, length: newText.length }); };// 主線程中創(chuàng)建 Worker 并接收解析結(jié)果 const container document.getElementById(output); const worker new Worker(./markdown.worker.js); worker.onmessage (event) { const { html } event.data; const temp document.createElement(div); temp.innerHTML html; container.appendChild(...temp.children); }; worker.postMessage({ fullText, renderedLength });注意Worker 版本適合把“解析字符串”從主線程移走但 DOM 替換本身仍要發(fā)生在主線程。如果想徹底避免主線程頻繁操作 DOM還需要對(duì)長(zhǎng)文本做分頁(yè)或虛擬滾動(dòng)這部分屬于下游工程。6. 長(zhǎng)回復(fù)場(chǎng)景下的 API 與流式鏈路設(shè)計(jì)6.1 流式響應(yīng)的數(shù)據(jù)格式主流 LLM 接口都支持 SSE 或 fetch stream。服務(wù)端按事件流推送增量?jī)?nèi)容前端通過(guò) ReadableStream 讀取。data: {id:1,delta:你} data: {id:1,delta:好} data: {id:1,delta:今天繼續(xù)寫(xiě)這篇長(zhǎng)文}前端讀取流時(shí)注意用 TextDecoder 的{ stream: true }參數(shù)處理多字節(jié)字符被分包的情況否則中文可能亂碼。6.2 超時(shí)、中斷與重連長(zhǎng)回復(fù)接口不適合短超時(shí)。普通 REST 接口可能 10 到 30 秒超時(shí)但流式接口在生成一個(gè)幾千字回復(fù)時(shí)整體耗時(shí)可能達(dá)到幾十秒甚至幾分鐘。超時(shí)策略應(yīng)該基于“兩個(gè) chunk 之間的間隔”而不是“整個(gè)請(qǐng)求的總時(shí)長(zhǎng)”。前端還要處理中斷場(chǎng)景用戶點(diǎn)擊停止生成、頁(yè)面切換、桌面端 WebView 被系統(tǒng)回收。建議做好“流中斷時(shí)保留已生成文本”的快照邏輯。6.3 長(zhǎng)回復(fù)與批量任務(wù)流式渲染解決的是“用戶在頁(yè)面上看著內(nèi)容生成”的場(chǎng)景。一次生成即一個(gè)流式響應(yīng)。批量任務(wù)則不同把大量長(zhǎng)文本生成任務(wù)放進(jìn)隊(duì)列通過(guò)任務(wù) ID 輪詢或回調(diào)獲取結(jié)果。兩種模式對(duì)應(yīng)不同的接口設(shè)計(jì)。如果要做批量長(zhǎng)文生成可以這樣設(shè)計(jì)任務(wù)狀態(tài){ task_id: task_123456, status: running, total_chunks: 200, completed_chunks: 87, output: }批量任務(wù)不需要前端實(shí)時(shí)渲染每一段重點(diǎn)是任務(wù)進(jìn)度的可追蹤性和失敗重試。7. 性能觀察與對(duì)比方法7.1 前后對(duì)比的實(shí)驗(yàn)設(shè)計(jì)如果你想在項(xiàng)目里復(fù)現(xiàn)類(lèi)似優(yōu)化實(shí)驗(yàn)流程分四步。第一步固定測(cè)試文本。為了避免隨機(jī)性建議準(zhǔn)備一個(gè) 3000 到 5000 字的固定長(zhǎng)文本按固定間隔推送。第二步固定測(cè)試環(huán)境。同一瀏覽器、同一設(shè)備、關(guān)閉不必要的插件必要時(shí)用瀏覽器無(wú)痕模式。第三步記錄基線。用未優(yōu)化的版本跑一遍記錄 Long Task 數(shù)量、累計(jì)主線程阻塞時(shí)間和滾動(dòng)幀率。第四步切換優(yōu)化版本重復(fù)同樣流程對(duì)比數(shù)據(jù)。7.2 不要只盯著“倍數(shù)”官方說(shuō) 4 倍提升這個(gè)數(shù)字是從特定測(cè)試環(huán)境和指標(biāo)下得出的。你在自己的頁(yè)面里優(yōu)化后可能只提升了 30%也可能提升了 10 倍。這都很正常。關(guān)鍵是看主線程占用是否降下來(lái)了、長(zhǎng)任務(wù)是否變少、用戶能否在生成過(guò)程中流暢滾動(dòng)手動(dòng)閱讀。7.3 性能觀察的常見(jiàn)誤區(qū)第一個(gè)誤區(qū)是只看 TTFT。TTFT 只反映第一段內(nèi)容的到達(dá)時(shí)間長(zhǎng)回復(fù)的卡頓主要集中在后半程。第二個(gè)誤區(qū)是忽略滾動(dòng)場(chǎng)景。很多測(cè)試只盯著自動(dòng)輸出沒(méi)有在輸出過(guò)程中模擬手動(dòng)滾動(dòng)。第三個(gè)誤區(qū)是忘記檢查頁(yè)面內(nèi)存。長(zhǎng)期掛著一個(gè)超大 DOM 樹(shù)即使渲染不卡內(nèi)存也會(huì)持續(xù)增長(zhǎng)桌面端尤其明顯。8. 常見(jiàn)問(wèn)題與排查方法問(wèn)題現(xiàn)象可能原因排查方式解決方案長(zhǎng)文本滾動(dòng)卡頓高頻 DOM 更新占滿主線程Performance 面板查看 Long Task 頻率批量提交增量用 requestIdleCallback 調(diào)度代碼塊出現(xiàn)時(shí)頁(yè)面掉幀語(yǔ)法高亮在主線程同步執(zhí)行觀察代碼塊首次渲染時(shí)的耗時(shí)高亮任務(wù)放到 Worker 或延遲到空閑期打字輸入延遲明顯渲染任務(wù)和 input 事件搶占主線程輸入框事件響應(yīng)延遲分析降低渲染優(yōu)先級(jí)預(yù)留輸入事件處理間隙桌面端 WebView 內(nèi)存暴漲歷史節(jié)點(diǎn)持續(xù)增加沒(méi)有淘汰觀察 DOM 節(jié)點(diǎn)數(shù)和堆內(nèi)存曲線引入虛擬滾動(dòng)限制容器內(nèi)節(jié)點(diǎn)數(shù)流式輸出中斷代理或網(wǎng)關(guān)斷開(kāi)空閑連接查看網(wǎng)絡(luò)請(qǐng)求斷開(kāi)時(shí)間點(diǎn)配置更長(zhǎng)超時(shí)時(shí)間前端加自動(dòng)重連中文輸出亂碼TextDecoder 未用流式模式解碼檢查解碼參數(shù)使用 new TextDecoder() 并傳 { stream: true }頁(yè)面強(qiáng)制滾到底部打斷閱讀滾動(dòng)策略沒(méi)有區(qū)分用戶意圖觀察滾動(dòng)事件發(fā)生時(shí)機(jī)只在用戶位于底部時(shí)自動(dòng)滾動(dòng)這些問(wèn)題的共同點(diǎn)是不要讓一次性渲染任務(wù)長(zhǎng)時(shí)間占據(jù)瀏覽器主線程。9. 最佳實(shí)踐與使用建議9.1 工程落地建議第一次接入流式渲染時(shí)先用模擬接口跑通鏈路不要直接接真實(shí)模型。把“網(wǎng)絡(luò)接收、文本緩存、渲染提交、滾動(dòng)控制”四層拆開(kāi)分別測(cè)試。這樣出了問(wèn)題能快速定位。項(xiàng)目目錄建議分開(kāi)管理模型輸出文本、渲染后 HTML、高亮后的代碼塊、滾動(dòng)位置緩存。避免在狀態(tài)對(duì)象里存一整套扁平字符串然后每次全量重新生成。9.2 合規(guī)與安全邊界長(zhǎng)回復(fù)內(nèi)容可能包含代碼、文檔、個(gè)人信息。涉及業(yè)務(wù)數(shù)據(jù)時(shí)要確保流式接口有權(quán)限校驗(yàn)避免中間人截獲敏感內(nèi)容。接口服務(wù)最好限制訪問(wèn)范圍不要暴露到公網(wǎng)。如果生成結(jié)果涉及人臉、聲音、他人作品或未公開(kāi)文檔發(fā)布前必須確認(rèn)授權(quán)。流式渲染只是技術(shù)展示不能繞過(guò)內(nèi)容合規(guī)審核。10. 總結(jié)與下一步這次 Claude 網(wǎng)頁(yè)端與桌面端的長(zhǎng)回復(fù)流式渲染提速本質(zhì)是前端渲染鏈路的優(yōu)化不是模型輸出變快了。它提醒所有做 LLM 產(chǎn)品的人模型把文字“說(shuō)”出來(lái)只是完整鏈路的前半段后半段“讓用戶舒服地看到文字”是否高效直接決定產(chǎn)品體驗(yàn)。最值得先做的驗(yàn)證是在你自己的 Chat 頁(yè)面上用固定長(zhǎng)文本做一次基線測(cè)試看 Performance 面板里是否出現(xiàn)大量長(zhǎng)任務(wù)。如果長(zhǎng)任務(wù)密集就按本文的增量渲染、批量提交、Worker 解析三個(gè)方向逐步改造。最容易踩的坑是“只優(yōu)化了第一屏”。長(zhǎng)回復(fù)的卡頓通常出現(xiàn)在文本累計(jì)到一定長(zhǎng)度之后驗(yàn)證時(shí)一定要跑到長(zhǎng)文本后段手動(dòng)滾動(dòng)畫(huà)一畫(huà)輸入框敲幾個(gè)字整套體驗(yàn)順了才算真正完成。后續(xù)可以繼續(xù)擴(kuò)展的方向包括長(zhǎng)文本虛擬滾動(dòng)、代碼高亮按需加載、桌面端離線緩存、批量生成任務(wù)隊(duì)列。每一步都可以用同一套性能觀察流程驗(yàn)證效果。建議收藏備用。