摘要:調度系統,支持不同渲染優先級,對進行調度。調度帶來的限制調度系統也存在兩個問題。調度系統能力有限,只能在瀏覽器提供的能力范圍內進行調度,而無法影響比如的渲染回收周期。精讀關于調度系統的剖析,可以讀深入剖析這篇文章,感謝我們團隊的淡蒼提供。
1. 引言
這次介紹的文章是 scheduling-in-react,簡單來說就是 React 的調度系統,為了得到更順滑的用戶體驗。
畢竟前端做到最后,都是體驗優化,前端帶給用戶的價值核心就在于此。
2. 概述文章從 Dan 在 JSConf 提到的 Demo 說起:
這是一個測試性能的 Demo,隨著輸入框字符的增加,下方圖表展示的數據量會急速提升。在 Synchronous 與 Debounced 模式下的效果都不盡如人意,只有 Concurrent 模式下看起來是順暢的。
那么為什么普通的 Demo 會很卡呢?
這就涉及到瀏覽器 Event Loop 規則了。
JS 是單線程的,瀏覽器同一時間只能做一件事情,而肉眼能識別的刷新頻率在 60FPS 左右,這意味著我們需要在 16ms 之內完成 Demo 中的三件事:響應用戶輸入,做動畫,Dom 渲染。
然而目前幾乎所有框架都使用同步渲染模式,這意味著如果一個渲染函數執行時間超過了 16ms,則不可避免的發生卡頓。
總結一下有兩個主要問題:
長時間運行的任務造成頁面卡頓,我們需要保證所有任務能在幾毫秒內完成,這樣才能保證頁面的流暢。
不同任務優先級不同,比如響應用戶輸入的任務優先級就高于動畫。這個很好理解。
React 調度機制為了解決這個問題,React16 通過 Concurrent(并行渲染) 與 Scheduler(調度)兩個角度解決問題:
Concurrent: 將同步的渲染變成可拆解為多步的異步渲染,這樣可以將超過 16ms 的渲染代碼分幾次執行。
Scheduler: 調度系統,支持不同渲染優先級,對 Concurrent 進行調度。當然,調度系統對低優先級任務會不斷提高優先級,所以不會出現低優先級任務總得不到執行的情況。
為了保證不產生阻塞的感覺,調度系統會將所有待執行的回調函數存在一份清單中,在每次瀏覽器渲染時間分片間盡可能的執行,并將沒有執行完的內容 Hold 住留到下個分片處理。
Concurrent 的正式 API 會在 2019 Q2 發布,現在可以通過
ReactDOM.render(, rootElement );
只申明這個是不夠的,因為我們還沒有申明各函數執行的優先級。我們可以通過 npm i scheduler 包來申明函數的優先級:
import { unstable_next } from "scheduler"; function SearchBox(props) { const [inputValue, setInputValue] = React.useState(); function handleChange(event) { const value = event.target.value; setInputValue(value); unstable_next(function() { props.onChange(value); sendAnalyticsNotification(value); }); } return ; }
在 unstable_next() 作用域下的代碼優先級是 Normal,那么產生的效果是:
如果 props.onChange(value) 可以在 16ms 內執行完,則與不使用 unstable_next 沒有區別。
如果 props.onChange(value) 的執行時間過長,可能這個函數會在下次幾次的 Render 中陸續執行,不會阻塞后續的高優先級任務。
調度帶來的限制調度系統也存在兩個問題。
調度系統只能有一個,如果同時存在兩個調度系統,就無法保證調度正確性。
調度系統能力有限,只能在瀏覽器提供的能力范圍內進行調度,而無法影響比如 Html 的渲染、回收周期。
為了解決這個問題,Chrome 正在與 React、Polymer、Ember、Google Maps、Web Standars Community 共同創建一個 瀏覽器調度規范,提供瀏覽器級別 API,可以讓調度控制更底層的渲染時機,也保證調度器的唯一性。
3. 精讀關于 React 調度系統的剖析,可以讀 深入剖析 React Concurrent 這篇文章,感謝我們團隊的 淡蒼 提供。
簡單來說,一次 Render 一般涉及到許多子節點,而 Fiber 架構在 Render 階段可以暫停,一個一個節點的執行,從而實現了調度的能力。
React 調度能力的限制這意味著,如果你的 React 應用目前是流暢的,開啟 Concurrent 并不會對你的應用帶來性能體驗上的提升,如果你的 React 應用目前是卡頓的,或者在某些場景下是卡頓的,那么 Concurrent 或許可以挽救你一下,帶來一些改變。
正如《深入剖析 React Concurrent》一文提到的,如果你的應用沒有性能問題,就不要指望 React 調度能力有所幫助了。
這也是在說,如果一段代碼邏輯不存在性能問題,就不需要使用 Concurrent 優化,因為這種優化是無效的。我們需要能分辨哪些邏輯需要優化,哪些邏輯不要。
從現在開始嘗試 Function Component為了配合 React Schedule 的實現,學會使用 Function Component 模式編寫組件是很重要的,因為:
Class Component 的生命周期概念阻礙了 React 調度系統對任務的拆分。
調度系統可能對 componentWillMount 重復調用,使得 Class Component 模式下很容易寫出錯誤的代碼。
Function Component 遵循了更嚴格的副作用分離,這使得 Concurrent 執行過程不會引發意外效果。
React.lazy與 Concurrent 一起發布的,還有 React 組件動態 import 與載入方案。正常的組件載入是這樣的:
import OtherComponent from "./OtherComponent"; function MyComponent() { return (); }
但如果使用了 import() 動態載入,可以使用 React.lazy 讓動態引入的組件像普通組件一樣被使用:
const OtherComponent = React.lazy(() => import("./OtherComponent")); function MyComponent() { return (); }
如果要加入 Loading,就可以配合 Suspense 一起使用:
import React, { lazy, Suspense } from "react"; const OtherComponent = lazy(() => import("./OtherComponent")); function MyComponent() { return (Loading...
和 Concurrent 類似,React.lazy 方案也是一種對性能有益的組件加載方案。
調度分類調度分 4 個等級:
Immediate:立即執行,最高優先級。
render-blocking:會阻塞渲染的優先級,優先級類似 requestAnimationFrame。如果這種優先級任務不能被執行,就可能導致 UI 渲染被 block。
default:默認優先級,普通的優先級。優先級可以理解為 setTimeout(0) 的優先級。
idle:比如通知等任務,用戶看不到或者不在意的。
目前建議的 API 類似如下:
function mytask() { ... } myQueue = TaskQueue.default("render-blocking")
先創建一個執行隊列,并設置隊列的優先級。
taskId = myQueue.postTask(myTask,);
再提交隊列,拿到當前隊列的執行 id,通過這個 id 可以判斷隊列何時執行完畢。
myQueue.cancelTask(taskId);
必要的時候可以取消某個函數的執行。
4. 總結隨著 Hooks 的發布,即將到來的 Concurrent 與 Suspense 你是否準備好了呢?
筆者希望大家一起思考,這三種 API 會給前端開發帶來什么樣的改變?歡迎留言!
討論地址是:精讀《Scheduling in React》 · Issue #146 · dt-fe/weekly
如果你想參與討論,請 點擊這里,每周都有新的主題,周末或周一發布。前端精讀 - 幫你篩選靠譜的內容。
關注 前端精讀微信公眾號
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/103529.html
摘要:引言本周精讀的文章是,看看作者是如何解釋這個多態性含義的。讀完文章才發現,文章標題改為的多態性更妥當,因為整篇文章都在說,而使用場景不局限于。更多討論討論地址是精讀的多態性如果你想參與討論,請點擊這里,每周都有新的主題,周末或周一發布。 1 引言 本周精讀的文章是:surprising-polymorphism-in-react-applications,看看作者是如何解釋這個多態性含...
摘要:引言這個是針對的。一般結合使用,因為請求級別的緩存與具有頁面攔截功能的最配。本周精讀的文章是,介紹了瀏覽器緩存接口的基本語法。包含任意命名空間,可以通過創建或訪問。精讀筆者利用實現了純瀏覽器端的后端渲染。前端精讀幫你篩選靠譜的內容。 1 引言 caches 這個 API 是針對 Request Response 的。caches 一般結合 Service Worker 使用,因為請求級...
摘要:拿到的都是而不是原始值,且這個值會動態變化。精讀對于的與,筆者做一些對比。因此采取了作為優化方案只有當第二個依賴參數變化時才返回新引用。不需要使用等進行性能優化,所有性能優化都是自動的。前端精讀幫你篩選靠譜的內容。 1. 引言 Vue 3.0 的發布引起了軒然大波,讓我們解讀下它的 function api RFC 詳細了解一下 Vue 團隊是怎么想的吧! 首先官方回答了幾個最受關注的...
摘要:會自動觸發函數內回調函數的執行。因此利用并將依賴置為使代碼在所有渲染周期內,只在初始化執行一次。同時代碼里還對等公共方法進行了包裝,讓這些回調函數中自帶效果。前端精讀幫你篩選靠譜的內容。 1. 引言 react-easy-state 是個比較有趣的庫,利用 Proxy 創建了一個非常易用的全局數據流管理方式。 import React from react; import { stor...
摘要:未來可能成為官方之一。討論地址是精讀組件如果你想參與討論,請點擊這里,每周都有新的主題,周末或周一發布。前端精讀幫你篩選靠譜的內容。 1. 引言 為什么要了解 Function 寫法的組件呢?因為它正在變得越來越重要。 那么 React 中 Function Component 與 Class Component 有何不同? how-are-function-components-di...
閱讀 3266·2023-04-26 01:31
閱讀 1904·2023-04-25 22:08
閱讀 3457·2021-09-01 11:42
閱讀 2834·2019-08-30 12:58
閱讀 2176·2019-08-29 18:31
閱讀 2441·2019-08-29 17:18
閱讀 3072·2019-08-29 13:01
閱讀 2560·2019-08-28 18:22