Turbolog 引擎

影格如何透過遊程編碼合併為一次 console.log 呼叫,以及 CellBuffer、Chromium 細節與效能測試。

Turbolog 將每次 React 提交轉成一次 console.log 呼叫;若沒有儲存格變更,就不呼叫。

目標

  1. 每個有變更的影格只呼叫一次。
  2. 閒置時零呼叫。 未變更的影格會在建立字串之前回傳。
  3. 少量樣式引數。 密集的 100×32 儀表板共有 3200 個儲存格,使用 149 個 %c span。

處理流程

React ─▶ Yoga ─▶ CellBuffer ─▶ row-hash gate ─▶ RLE ─▶ console.log

CellBuffer

影格儲存在分別存放字元、顏色與屬性的扁平型別陣列中,只配置一次。

變更檢查閘門

每一列都會計算雜湊值。若沒有變更,驅動程式就提前回傳:

if (frame === null) return SKIPPED; // 0 console callsconsole.log(frame.format, ...frame.args);

影格切換

Turbolog 會附加影格,且只在第一個影格、呼叫 invalidate() 後、堆疊達 100 個影格後閒置時,以及達 300 個影格時清除主控台。DevTools 會立即移除已清除的訊息,但新訊息的繪製受 50 ms 的節流限制,因此每個影格都清除會讓主控台閃現空白。附加的影格會在單次繪製內切換,並透過零寬度的遮幕 span 將前一個影格擋在視野之外。向上捲動即可查看先前的影格。

影格更新速率控制在約 15 fps。更快的影格會重設 DevTools 的節流計時,並遭到丟棄。

游程編碼

相符的儲存格會合併成一個 %c span。span 會跨越換行延續,CSS 字串則以字串駐留方式共用。

console.log("%c▼ Text.js%c ready", "color:#ededed;font-weight:700", "color:#45a557");

Chromium 細節

  • 字面上的 % 會跳脫為 %%。
  • 網址與 path:line 文字會插入 word joiner,避免 DevTools 重新設定其樣式。
  • span 只使用 CSS 個別屬性。DevTools 會將每個展開後的屬性複製到每一行。
  • span 經過調整,讓背景平鋪時不留間隙。

Firefox 與 Safari

Chromium 將 %c span 的每一行配置為行內區塊。Firefox 與 Safari 則讓 span 維持行內顯示,因此會忽略垂直邊距,並將過長的列換行。CssConsoleDriver 透過 CSS 功能檢查偵測瀏覽器,並針對這兩種主控台設定 14 px 行高且不留邊距,使用 text-wrap-mode: nowrap 關閉換行,再以 line-height: 100vh 遮幕將先前的影格推到視野之外。配合主控台尺寸時,會為 Firefox 的來源連結欄預留空間。Safari 將 Menlo 放在字型堆疊的首位,因為網頁無法使用由使用者安裝、但 Web Inspector 可能用來繪製文字的 SF Mono。將 browser 傳給 createConsoleRoot,即可自行選擇主控台。

效能基準測試

packages/core/test/perf.test.ts 在密集的 100×32 儀表板上測試,取 1000 個影格的平均值(Apple M5 Pro,Bun 1.4.4):

影格時間%c span 數
完整重繪(版面配置、繪製、編碼)0.163 ms149
單列編輯0.011 ms149
閒置0.000 ms0

狀態頁面會在你的瀏覽器中執行相同的處理流程。在 Playground 的示範執行期間,於 DevTools 中執行 text.stats()。

在 GitHub 編輯此頁