最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

react render的原理及觸發(fā)時機說明

 更新時間:2023年02月12日 13:30:03   作者:嘻嘍嘍嘍  
這篇文章主要介紹了react render的原理及觸發(fā)時機說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

react render的原理及觸發(fā)時機

理解react的render函數,要從這三點來認識。原理、執(zhí)行時機、總結。

原理

在類組件和函數組件中,render函數的形式是不同的。

在類組件中render函數指的就是render方法;而在函數組件中,指的就是整個函數組件。

class?Foo?extends?React.Component?{
????render()?{ //類組件中

????????return?<h1>?Foo?</h1>;

????}

}
function?Foo()?{? //函數組件中

????return?<h1>?Foo?</h1>;

}

在render函數中的jsx語句會被編譯成我們熟悉的js代碼

render過程中,React 將新調用的 render函數返回的樹與舊版本的樹進行比較,這一步是決定如何更新 DOM 的必要步驟,然后進行 diff 比較,更新 DOM樹 

觸發(fā)時機

render的執(zhí)行時機主要分成了兩部分:

類組件調用 setState 修改狀態(tài):

class Foo extends React.Component {
? state = { count: 0 };
?
? increment = () => {
? ? const { count } = this.state;
?
? ? const newCount = count < 10 ? count + 1 : count;
?
? ? this.setState({ count: newCount });
? };
?
? render() {
? ? const { count } = this.state;
? ? console.log("Foo render");
?
? ? return (
? ? ? <div>
? ? ? ? <h1> {count} </h1>
? ? ? ? <button onClick={this.increment}>Increment</button>
? ? ? </div>
? ? );
? }

}

函數組件通過useState hook修改狀態(tài):

function Foo() {
? const [count, setCount] = useState(0);
?
? function increment() {
? ? const newCount = count < 10 ? count + 1 : count;
? ? setCount(newCount);
? }
?
? console.log("Foo render");
??
? return (
? ? <div>
? ? ? <h1> {count} </h1>
? ? ? <button onClick={increment}>Increment</button>
? ? </div>
? );?

}

函數組件通過useState這種形式更新數據,當數組的值不發(fā)生改變了,就不會觸發(fā)render

小結一下:

render函數里面可以編寫JSX,轉化成createElement這種形式,用于生成虛擬DOM,最終轉化成真實DOM

在React 中,類組件只要執(zhí)行了 setState 方法,就一定會觸發(fā) render 函數執(zhí)行,函數組件使用useState更改狀態(tài)不一定導致重新render

組件的props 改變了,不一定觸發(fā) render 函數的執(zhí)行,但是如果 props 的值來自于父組件或者祖先組件的 state

在這種情況下,父組件或者祖先組件的 state 發(fā)生了改變,就會導致子組件的重新渲染

所以,一旦執(zhí)行了setState就會執(zhí)行render方法,useState 會判斷當前值有無發(fā)生改變確定是否執(zhí)行render方法,一旦父組件發(fā)生渲染,子組件也會渲染

react Scheduler 原理

學習react也有一段時間了,最近零零碎碎看了些東西,總覺得改寫點東西沉淀下,聯系到react快速響應的理念,我覺得時間切片的使用是再出色不過了,時間切片的使用離不開scheduler,那就談談scheduler吧

scheduler是什么?

react16開始整個架構分成了三層,scheduler,Reconciler,renderer,因為為了實現將一個同步任務變成異步的可中斷的任務,react提出了fiber,因為最開始用的是stack,任務是無法中斷的,js執(zhí)行時間太長時會影響頁面的渲染造成卡頓,fiber中任務是可以終端,但是中斷的任務怎么連上,什么時間執(zhí)行,哪個先執(zhí)行,這都屬于是新的問題,因此scheduler出生了,以瀏覽器是否有剩余時間作為任務中斷的標準,那么我們需要一種機制,當瀏覽器有剩余時間時,scheduler會通知我們,同時scheduler會進行一系列的任務優(yōu)先級判斷,保證任務時間合理分配。

總結下scheduler的兩個功能:

  • 時間切片
  • 優(yōu)先級調度

時間切片

JS腳本執(zhí)行和瀏覽器布局、繪制不能同時執(zhí)行。在每16.6ms時間內,需要完成 JS腳本執(zhí)行 ----- 樣式布局 ----- 樣式繪制,當JS執(zhí)行時間過長,超出了16.6ms,這次刷新就沒有時間執(zhí)行樣式布局和樣式繪制了。

頁面掉幀,造成卡頓。時間切片是在瀏覽器每一幀的時間中,預留一些時間給JS線程,React利用這部分時間更新組件,預留的初始時間是5ms。

超過5ms,React將中斷js,等下一幀時間到來繼續(xù)執(zhí)行js。其實瀏覽器本身已經實現了時間切片的功能,這個API叫requestIdleCallback,requestIdleCallback 是 window 屬性上的方法,它的作用是在瀏覽器一幀的剩余空閑時間內執(zhí)行優(yōu)先度相對較低的任務。

但是由于requestIdleCallback 的這兩個缺陷,react決定自己模擬時間切片

  • 1.瀏覽器兼容不好的問題
  • 2.requestIdleCallback 的 FPS 只有 20,也就是 50ms 刷新一次,遠遠低于頁面流暢度的要求

回顧一個知識瀏覽器在16.6ms里面要做哪些事情

宏任務-- 微任務 -- requestAnimationFrame -- 瀏覽器重排/重繪 -- requestIdleCallback

我們可以一起來看下時間切片應該放在哪里,首先排除requestIdleCallback,缺點上文已經提到了,實際上時間切片是放在宏任務里面的,可以先說下為什么不放在其他地方的原因:

1.為什么不是微任務里面

微任務將在頁面更新前全部執(zhí)行完,所以達不到「將主線程還給瀏覽器」的目的。

2.為什么不使用requestAnimationFrame

如果第一次任務調度不是由 rAF() 觸發(fā)的,例如直接執(zhí)行 scheduler.scheduleTask(),那么在本次頁面更新前會執(zhí)行一次 rAF() 回調,該回調就是第二次任務調度。所以使用 rAF() 實現會導致在本次頁面更新前執(zhí)行了兩次任務。

為什么是兩次,而不是三次、四次?因為在 rAF() 的回調中再次調用 rAF(),會將第二次 rAF() 的回調放到下一幀前執(zhí)行,而不是在當前幀前執(zhí)行。

另一個原因是 rAF() 的觸發(fā)間隔時間不確定,如果瀏覽器間隔了 10ms 才更新頁面,那么這 10ms 就浪費了。(現有 WEB 技術中并沒有規(guī)定瀏覽器應該什么何時更新頁面,所以通常認為是在一次宏任務完成之后,瀏覽器自行判斷當前是否應該更新頁面。如果需要更新頁面,則執(zhí)行 rAF() 的回調并更新頁面。否則,就執(zhí)行下一個宏任務。)

3.既然是宏任務,那么是settimeout嗎?

遞歸執(zhí)行 setTimeout(fn, 0) 時,最后間隔時間會變成 4 毫秒,而不是最初的 1 毫秒,因為settimeout的執(zhí)行時機是和js執(zhí)行有關的,遞歸是會不準,最終使用 MessageChannel 產生宏任務,但是由于兼容,如果當前宿主環(huán)境不支持MessageChannel,則使用setTimeout。

在React的render階段,開啟Concurrent Mode時,每次遍歷前,都會通過Scheduler提供的shouldYield方法判斷是否需要中斷遍歷,使瀏覽器有時間渲染:

function workLoopConcurrent() {
? // Perform work until Scheduler asks us to yield
? while (workInProgress !== null && !shouldYield()) {
? ? performUnitOfWork(workInProgress);
? }
}

是否中斷的依據,最重要的一點便是每個任務的剩余時間是否用完。

在Schdeduler中,為任務分配的初始剩余時間為5ms。如果shouldYield為true,任務就會中斷,中斷之后再次執(zhí)行就要用到調度了

任務調度

Scheduler對外暴露了一個方法unstable_runWithPriority,這個方法可以用來獲取優(yōu)先級

unction unstable_runWithPriority(priorityLevel, eventHandler) {
? switch (priorityLevel) {
? ? case ImmediatePriority:
? ? case UserBlockingPriority:
? ? case NormalPriority:
? ? case LowPriority:
? ? case IdlePriority:
? ? ? break;
? ? default:
? ? ? priorityLevel = NormalPriority;
? }

//。。。省略
}

可以看到有5種優(yōu)先級,比如,我們知道commit階段是同步執(zhí)行的??梢钥吹剑琧ommit階段的起點commitRoot方法的優(yōu)先級為ImmediateSchedulerPriority。

ImmediateSchedulerPriority即ImmediatePriority的別名,為最高優(yōu)先級,會立即執(zhí)行??墒莾?yōu)先級只是一個名稱,react如何判斷優(yōu)先級的高低呢,這里我覺得和操作系統(tǒng)里面的一些概念還是挺相似的
給不同任務給上過期時間,誰快過期了就先執(zhí)行誰

var timeout;
switch (priorityLevel) {
? case ImmediatePriority:
? ? timeout = IMMEDIATE_PRIORITY_TIMEOUT;
? ? break;
? case UserBlockingPriority:
? ? timeout = USER_BLOCKING_PRIORITY_TIMEOUT;
? ? break;
? case IdlePriority:
? ? timeout = IDLE_PRIORITY_TIMEOUT;
? ? break;
? case LowPriority:
? ? timeout = LOW_PRIORITY_TIMEOUT;
? ? break;
? case NormalPriority:
? default:
? ? timeout = NORMAL_PRIORITY_TIMEOUT;
? ? break;
}

var expirationTime = startTime + timeout;
// Times out immediately
var IMMEDIATE_PRIORITY_TIMEOUT = -1;
// Eventually times out
var USER_BLOCKING_PRIORITY_TIMEOUT = 250;
var NORMAL_PRIORITY_TIMEOUT = 5000;
var LOW_PRIORITY_TIMEOUT = 10000;
// Never times out
var IDLE_PRIORITY_TIMEOUT = maxSigned31BitInt;

可以看到 IMMEDIATE_PRIORITY_TIMEOUT =-1,說明比當前時間還早,已經過期,必須快執(zhí)行,初此之外,react新增了兩個隊列:已就緒任務 ,未就緒任務

所以,Scheduler存在兩個隊列:timerQueue:保存未就緒任務,taskQueue:保存已就緒任務

每當有新的未就緒的任務被注冊,我們將其插入timerQueue并根據開始時間重新排列timerQueue中任務的順序。當timerQueue中有任務就緒,即startTime <= currentTime,我們將其取出并加入taskQueue。

取出taskQueue中最早過期的任務并執(zhí)行他。

簡單介紹下scheduler的原理,其實要更多了解scheduler,還要再看看lane模型,這塊之后再說吧,還有fiber啥的,有時間再寫。

總結

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • React用法之高階組件的用法詳解

    React用法之高階組件的用法詳解

    高階組件也就是我們常說的HOC,是React中用于復用組件邏輯的一種高級技巧。這篇文章主要通過一些示例帶大家學習一下高階組件的使用,希望對大家有所幫助
    2023-04-04
  • 在React中實現分塊導出大量數據表格并壓縮成圖片的解決方案

    在React中實現分塊導出大量數據表格并壓縮成圖片的解決方案

    在現代Web開發(fā)中,處理和展示大量數據是一個常見的挑戰(zhàn),特別是在使用React框架時,我們經常需要將這些數據以表格的形式展示,并提供導出功能,本文將介紹如何在React中實現一個高效、分塊導出大量數據表格,并將其壓縮為圖片的解決方案,需要的朋友可以參考下
    2024-12-12
  • create-react-app全家桶router?mobx全局安裝配置

    create-react-app全家桶router?mobx全局安裝配置

    這篇文章主要為大家介紹了create-react-app全家桶router?mobx全局安裝配置,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • React如何使用refresh_token實現無感刷新頁面

    React如何使用refresh_token實現無感刷新頁面

    本文主要介紹了React如何使用refresh_token實現無感刷新頁面,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-04-04
  • react中使用usestate踩坑及解決

    react中使用usestate踩坑及解決

    這篇文章主要介紹了react中使用usestate踩坑及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • 用react-redux實現react組件之間數據共享的方法

    用react-redux實現react組件之間數據共享的方法

    這篇文章主要介紹了用react-redux實現react組件之間數據共享的方法,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-06-06
  • React?useEffect異步操作常見問題小結

    React?useEffect異步操作常見問題小結

    本文主要介紹了React?useEffect異步操作常見問題小結,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-06-06
  • vite+react+tailwindcss的簡單使用方式

    vite+react+tailwindcss的簡單使用方式

    這篇文章主要介紹了vite+react+tailwindcss的簡單使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • React虛擬渲染實現50個或者一百個圖表渲染

    React虛擬渲染實現50個或者一百個圖表渲染

    這篇文章主要為大家介紹了React虛擬渲染實現50個或者100個圖表渲染的實現,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • React?less?實現縱橫柱狀圖示例詳解

    React?less?實現縱橫柱狀圖示例詳解

    這篇文章主要介紹了React?less?實現縱橫柱狀圖示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09

最新評論

石渠县| 罗山县| 亳州市| 丁青县| 新竹县| 四会市| 习水县| 屯昌县| 山东| 伊宁县| 灵台县| 桃江县| 明溪县| 浙江省| 哈密市| 那曲县| 青阳县| 卓尼县| 社旗县| 门源| 朝阳市| 金昌市| 腾冲县| 东港市| 六枝特区| 阜平县| 鹤峰县| 百色市| 云南省| 乐清市| 凭祥市| 天气| 江源县| 青神县| 古交市| 庄浪县| 平山县| 牙克石市| 丰都县| 仁寿县| 临澧县|