跳到主要內容
黯羽輕揚每天積累一點點

React 16

免費2017-12-31#JS#React 16 killer feature#React 16 features#React async rendering#react异步渲染#react增量渲染

看看憋了 2 年的大招有沒有帶來什麼 killer feature?

一. 特性

fragment

模版支援 fragmentstring 類型,對應 ReactElement 陣列和字串

v16.2.0 還提供了 JSX 的 fragment 支援<></>

error boundary

元件級 錯誤處理,支援擷取子元件樹內部異常,UI 層的兜底方案

portal

允許元件樹與 DOM 樹結構不一致,用於 hovercards, tooltips 等場景

例如 tooltip 在 DOM 結構上 target 與 tip 一般是兄弟關係(佈局需要),而邏輯上 tip 是屬於 target 的,是父子關係,portals 特性用來處理這種場景

特殊的,事件冒泡經過處理,portals 元件的父元件仍然能接到冒泡通知(React 16 之前就內建了用來抹平 DOM 事件冒泡差異的事件系統,這裡順便支援 拐彎冒泡 示例

support for custom DOM attributes

之前內建了 HTML/SVG 屬性名白名單,自定義屬性會被攔截並忽略掉,React 16 去掉了這個限制

去掉該限制有 2 個原因,其一,這層內建的屬性過濾對於非標準的(比如 proposal 階段的)新屬性和其它庫/框架(比如 Angular, Polymer)很 不友好;其二,bundle 裡要內建一份體積不小的屬性白名單,維護起來還 挺麻煩

improved server-side rendering

號稱比 React 15 快 3 倍(benchmark 場景,某業務場景據說 1.3 倍),做了幾件事:

  • 支援 stream

  • 構建時去掉了多餘的 process.env(在 Node 環境存取這個變數很耗時)存取

  • client 不再計算 checksum,而是儘量複用現有 DOM(與 貫徹落實 DOM node 複用的 inferno 神似,但 inferno 複用好像遇到一些問題,現在只作為可選項而不是亮點特性提供)

注意:React 16 貌似也存在 一些 DOM node 複用的問題

However, it’s dangerous to have missing nodes on the server render as this might cause sibling nodes to be created with incorrect attributes.

P.S. 具體要注意哪些危險場景,官方後面可能會給出專門的部落格,暫時沒有說清楚

reduced file size

React bundle 瘦身(重構,扁平化打包策略,並換用 rollup),體積小了 30%

二. SSR

變化最大的應該是 SSR,這次認真實現了一下(之前的 SSR 像是地上撿的)

1. 新 API

server 側新增了 renderToNodeStream, renderToStaticNodeStream 分別對應 renderToString, renderToStaticMarkup

client 側新增了 hydrate

2. 寬鬆的一致性校驗

client 側校驗沒那麼嚴格了:

  • React 15 中,client 會對拿到的 SSR 結果做字元級的一致性校驗,一點不匹配就由 client 重新生成並整個替掉

  • React 16 允許屬性順序不一致,而且不給自動修復不一致的屬性,而且遇到不匹配的標籤結構,會做子樹級修改,而不是整個替掉

另外,還去掉了 Server HTML 結構上的 checksum(data-react-checksum)以及 id(data-reactid),響應體大小會降低不少:

<!-- react 15 -->
<div data-reactroot="" data-reactid="1"
    data-react-checksum="122239856">
  <!-- react-text: 2 -->This is some <!-- /react-text -->
  <span data-reactid="3">server-generated</span>
  <!-- react-text: 4--> <!-- /react-text -->
  <span data-reactid="5">HTML.</span>
</div>

<!-- react 16 -->
<div data-reactroot="">
  This is some <span>server-generated</span> <span>HTML.</span>
</div>

3. 性能優化

預設去掉了多餘的 process.env.NODE_ENV 存取,不需要手動編譯去掉

SSR 不再建立一次性的 virtual DOM,整個快了不少

支援 stream,帶來的性能優勢如下:

  • server 邊造邊發,而不用等待 SSR 完畢才一次完整發過來,TTFB(the time to first byte)更快

  • client 邊接邊畫,而不用等到響應內容完整了才開始繪製,解析、繪製、外部資源載入等時間點都提前了

4. 不支援 Error Boundary 和 Portal

React 16 SSR 不支援 Error BoundaryPortal

服務端子元件渲染出錯,不會被 Error Boundary 攔住。為了 stream 性能優勢,犧牲了 Error Boundary:

This is intentional / a known limitation. With streaming rendering it's impossible to "call back" markup that has already been sent, and we opted to keep renderToString and renderToNodeStream's output identical.

不僅 renderToNodeStream, renderToStaticNodeStream 不支援 Error Boundary,renderToString 也不支援,如上面說的,為了保持輸出結果一致,沒有維護 2 套機制

P.S. 關於 SSR Error Boundary 的更多資訊,請查看 componentDidCatch doesn't work in React 16's renderToString

而 Portal 特性可能造成「回流」,與 Error Boundary 是一個道理,在 stream 機制下無法支援(想要往已經發送出去的 stream 裡插入 Portal 內容,當然不可能)

三. Fiber

全新的核心架構,(花了 2 年)整個重寫了元件渲染機制,最關鍵的特性是 非同步渲染(async rendering),實現了可調度渲染(徹底解決 mount 流程一旦開始就無法中斷的問題)

重構過程

這樣龐大的一個東西,傷筋動骨的重構執行過程很有意思。簡單地說:

  • 不拉新分支去搞。而是透過 useFiber 特性開關切換,說是為了簡化日常維護/衝突處理等

  • 第一步做個骨架(skeleton)出來。支援部分 API,再慢慢跑通所有測試用例(所謂 TDD,測試驅動開發,最後搞出來 2000 個 case)

  • 工程化輔助手段。包括 進度追蹤、單測結果追蹤(便於發現一次提交修復了什麼,幹壞了什麼,手段非常簡單:把 tests-failing.txt, tests-passing.txt 添加到 git 追蹤)、持續的生產環境驗證(所謂 dogfooding,從早期到最後單測通過的整個過程都在不斷地進行「實戰」驗證,算是一種 看得見的信念

  • 找塊 合適的業務 作為試驗田(testbed)。差不多穩定後,透過實際業務來證明 ready for production,透過 A/B 測試出數據,讓 2 億用戶幫忙感受一下,後來再切到全量;同時對內系統全切,擴大驗證場景;最後再對 React Native 應用來個灰度

  • 不直接上新機制。暫時仍然以同步方式執行(雖然 Fiber 支援非同步),準備 再憋幾個月,好平滑過渡

P.S. 具體重構過程見 React 16: A look inside an API-compatible rewrite of our frontend UI library

所以 暫時不支援 非同步渲染:

This initial React 16.0 release is mostly focused on compatibility with existing apps. It does not enable asynchronous rendering yet. We will introduce an opt-in to the async mode later during React 16.x. We don't expect React 16.0 to make your apps significantly faster or slower, but we'd love to know if you see improvements or regressions.

優勢

  • 新特性

元件級錯誤處理、render 傳回多元件等之前不太容易實現的特性,重構之後都可以造出來了

  • 體驗上的優勢

Fiber 並 不一定更快,但會更流暢(拆分渲染任務並均衡調度,避免長時間佔用主執行緒),另外還有任務優先級控制,讓動畫等優先執行

差異相當明顯,見 React Stack vs Fiber

參考資料

評論

暫無評論,快來發表你的看法吧

提交評論