欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

react render的原理及觸發(fā)時(shí)機(jī)說(shuō)明

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

react render的原理及觸發(fā)時(shí)機(jī)

理解react的render函數(shù),要從這三點(diǎn)來(lái)認(rèn)識(shí)。原理、執(zhí)行時(shí)機(jī)、總結(jié)。

原理

在類(lèi)組件和函數(shù)組件中,render函數(shù)的形式是不同的。

在類(lèi)組件中render函數(shù)指的就是render方法;而在函數(shù)組件中,指的就是整個(gè)函數(shù)組件。

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

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

????}

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

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

}

在render函數(shù)中的jsx語(yǔ)句會(huì)被編譯成我們熟悉的js代碼

render過(guò)程中,React 將新調(diào)用的 render函數(shù)返回的樹(shù)與舊版本的樹(shù)進(jìn)行比較,這一步是決定如何更新 DOM 的必要步驟,然后進(jìn)行 diff 比較,更新 DOM樹(shù) 

觸發(fā)時(shí)機(jī)

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

類(lèi)組件調(diào)用 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>
? ? );
? }

}

函數(shù)組件通過(guò)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>
? );?

}

函數(shù)組件通過(guò)useState這種形式更新數(shù)據(jù),當(dāng)數(shù)組的值不發(fā)生改變了,就不會(huì)觸發(fā)render

小結(jié)一下:

render函數(shù)里面可以編寫(xiě)JSX,轉(zhuǎn)化成createElement這種形式,用于生成虛擬DOM,最終轉(zhuǎn)化成真實(shí)DOM

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

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

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

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

react Scheduler 原理

學(xué)習(xí)react也有一段時(shí)間了,最近零零碎碎看了些東西,總覺(jué)得改寫(xiě)點(diǎn)東西沉淀下,聯(lián)系到react快速響應(yīng)的理念,我覺(jué)得時(shí)間切片的使用是再出色不過(guò)了,時(shí)間切片的使用離不開(kāi)scheduler,那就談?wù)剆cheduler吧

scheduler是什么?

react16開(kāi)始整個(gè)架構(gòu)分成了三層,scheduler,Reconciler,renderer,因?yàn)闉榱藢?shí)現(xiàn)將一個(gè)同步任務(wù)變成異步的可中斷的任務(wù),react提出了fiber,因?yàn)樽铋_(kāi)始用的是stack,任務(wù)是無(wú)法中斷的,js執(zhí)行時(shí)間太長(zhǎng)時(shí)會(huì)影響頁(yè)面的渲染造成卡頓,fiber中任務(wù)是可以終端,但是中斷的任務(wù)怎么連上,什么時(shí)間執(zhí)行,哪個(gè)先執(zhí)行,這都屬于是新的問(wèn)題,因此scheduler出生了,以瀏覽器是否有剩余時(shí)間作為任務(wù)中斷的標(biāo)準(zhǔn),那么我們需要一種機(jī)制,當(dāng)瀏覽器有剩余時(shí)間時(shí),scheduler會(huì)通知我們,同時(shí)scheduler會(huì)進(jìn)行一系列的任務(wù)優(yōu)先級(jí)判斷,保證任務(wù)時(shí)間合理分配。

總結(jié)下scheduler的兩個(gè)功能:

  • 時(shí)間切片
  • 優(yōu)先級(jí)調(diào)度

時(shí)間切片

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

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

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

但是由于requestIdleCallback 的這兩個(gè)缺陷,react決定自己模擬時(shí)間切片

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

回顧一個(gè)知識(shí)瀏覽器在16.6ms里面要做哪些事情

宏任務(wù)-- 微任務(wù) -- requestAnimationFrame -- 瀏覽器重排/重繪 -- requestIdleCallback

我們可以一起來(lái)看下時(shí)間切片應(yīng)該放在哪里,首先排除requestIdleCallback,缺點(diǎn)上文已經(jīng)提到了,實(shí)際上時(shí)間切片是放在宏任務(wù)里面的,可以先說(shuō)下為什么不放在其他地方的原因:

1.為什么不是微任務(wù)里面

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

2.為什么不使用requestAnimationFrame

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

為什么是兩次,而不是三次、四次?因?yàn)樵?rAF() 的回調(diào)中再次調(diào)用 rAF(),會(huì)將第二次 rAF() 的回調(diào)放到下一幀前執(zhí)行,而不是在當(dāng)前幀前執(zhí)行。

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

3.既然是宏任務(wù),那么是settimeout嗎?

遞歸執(zhí)行 setTimeout(fn, 0) 時(shí),最后間隔時(shí)間會(huì)變成 4 毫秒,而不是最初的 1 毫秒,因?yàn)閟ettimeout的執(zhí)行時(shí)機(jī)是和js執(zhí)行有關(guān)的,遞歸是會(huì)不準(zhǔn),最終使用 MessageChannel 產(chǎn)生宏任務(wù),但是由于兼容,如果當(dāng)前宿主環(huán)境不支持MessageChannel,則使用setTimeout。

在React的render階段,開(kāi)啟Concurrent Mode時(shí),每次遍歷前,都會(huì)通過(guò)Scheduler提供的shouldYield方法判斷是否需要中斷遍歷,使瀏覽器有時(shí)間渲染:

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

是否中斷的依據(jù),最重要的一點(diǎn)便是每個(gè)任務(wù)的剩余時(shí)間是否用完。

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

任務(wù)調(diào)度

Scheduler對(duì)外暴露了一個(gè)方法unstable_runWithPriority,這個(gè)方法可以用來(lái)獲取優(yōu)先級(jí)

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

//。。。省略
}

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

ImmediateSchedulerPriority即ImmediatePriority的別名,為最高優(yōu)先級(jí),會(huì)立即執(zhí)行。可是優(yōu)先級(jí)只是一個(gè)名稱(chēng),react如何判斷優(yōu)先級(jí)的高低呢,這里我覺(jué)得和操作系統(tǒng)里面的一些概念還是挺相似的
給不同任務(wù)給上過(guò)期時(shí)間,誰(shuí)快過(guò)期了就先執(zhí)行誰(shuí)

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,說(shuō)明比當(dāng)前時(shí)間還早,已經(jīng)過(guò)期,必須快執(zhí)行,初此之外,react新增了兩個(gè)隊(duì)列:已就緒任務(wù) ,未就緒任務(wù)

所以,Scheduler存在兩個(gè)隊(duì)列:timerQueue:保存未就緒任務(wù),taskQueue:保存已就緒任務(wù)

每當(dāng)有新的未就緒的任務(wù)被注冊(cè),我們將其插入timerQueue并根據(jù)開(kāi)始時(shí)間重新排列timerQueue中任務(wù)的順序。當(dāng)timerQueue中有任務(wù)就緒,即startTime <= currentTime,我們將其取出并加入taskQueue。

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

簡(jiǎn)單介紹下scheduler的原理,其實(shí)要更多了解scheduler,還要再看看lane模型,這塊之后再說(shuō)吧,還有fiber啥的,有時(shí)間再寫(xiě)。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • react中使用swiper的具體方法

    react中使用swiper的具體方法

    本篇文章主要介紹了react中使用swiper的具體方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • react嵌套路由實(shí)現(xiàn)TabBar的實(shí)現(xiàn)

    react嵌套路由實(shí)現(xiàn)TabBar的實(shí)現(xiàn)

    本文主要介紹了react嵌套路由實(shí)現(xiàn)TabBar的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • react PropTypes校驗(yàn)傳遞的值操作示例

    react PropTypes校驗(yàn)傳遞的值操作示例

    這篇文章主要介紹了react PropTypes校驗(yàn)傳遞的值操作,結(jié)合實(shí)例形式分析了react PropTypes針對(duì)傳遞的值進(jìn)行校驗(yàn)操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2020-04-04
  • React Native之TextInput組件解析示例

    React Native之TextInput組件解析示例

    本篇文章主要介紹了React Native之TextInput組件解析示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • 使用react遍歷對(duì)象生成dom

    使用react遍歷對(duì)象生成dom

    這篇文章主要介紹了使用react遍歷對(duì)象生成dom問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • React Native 自定義下拉刷新上拉加載的列表的示例

    React Native 自定義下拉刷新上拉加載的列表的示例

    本篇文章主要介紹了React Native 自定義下拉刷新上拉加載的列表的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • 為什么說(shuō)form元素是React的未來(lái)

    為什么說(shuō)form元素是React的未來(lái)

    這篇文章主要介紹了為什么說(shuō)form元素是React的未來(lái),本文會(huì)帶你聊聊React圍繞form的布局與發(fā)展,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • React中setState/useState的使用方法詳細(xì)介紹

    React中setState/useState的使用方法詳細(xì)介紹

    這篇文章主要介紹了React中setState/useState的使用方法,useState 和 setState 在React開(kāi)發(fā)過(guò)程中 使用很頻繁,但很多人都停留在簡(jiǎn)單的使用階段,并沒(méi)有正在了解它們的執(zhí)行機(jī)制
    2023-04-04
  • React css-in-js基礎(chǔ)介紹與應(yīng)用

    React css-in-js基礎(chǔ)介紹與應(yīng)用

    隨著React、Vue等支持組件化的MVVM前端框架越來(lái)越流行,在js中直接編寫(xiě)css的技術(shù)方案也越來(lái)越被大家所接受。為什么前端開(kāi)發(fā)者們更青睞于這些css-in-js的方案呢,下面帶你了解它
    2022-09-09
  • 簡(jiǎn)單的React SSR服務(wù)器渲染實(shí)現(xiàn)

    簡(jiǎn)單的React SSR服務(wù)器渲染實(shí)現(xiàn)

    這篇文章主要介紹了簡(jiǎn)單的React SSR服務(wù)器渲染實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12

最新評(píng)論