真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

如何理解React中的優(yōu)先級

這篇文章主要講解了“如何理解React中的優(yōu)先級”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“如何理解React中的優(yōu)先級”吧!

目前成都創(chuàng)新互聯(lián)公司已為近1000家的企業(yè)提供了網(wǎng)站建設、域名、網(wǎng)頁空間、網(wǎng)站托管維護、企業(yè)網(wǎng)站設計、漠河網(wǎng)站維護等服務,公司將堅持客戶導向、應用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。

UI產(chǎn)生交互的根本原因是各種事件,這也就意味著事件與更新有著直接關系。不同事件產(chǎn)生的更新,它們的優(yōu)先級是有差異的,所以更新優(yōu)先級的根源在于事件的優(yōu)先級。一個更新的產(chǎn)生可直接導致React生成一個更新任務,最終這個任務被Scheduler調(diào)度。

所以在React中,人為地將事件劃分了等級,最終目的是決定調(diào)度任務的輕重緩急,因此,React有一套從事件到調(diào)度的優(yōu)先級機制。

本文將圍繞事件優(yōu)先級、更新優(yōu)先級、任務優(yōu)先級、調(diào)度優(yōu)先級,重點梳理它們之間的轉(zhuǎn)化關系。

  •  事件優(yōu)先級:按照用戶事件的交互緊急程度,劃分的優(yōu)先級

  •  更新優(yōu)先級:事件導致React產(chǎn)生的更新對象(update)的優(yōu)先級(update.lane)

  •  任務優(yōu)先級:產(chǎn)生更新對象之后,React去執(zhí)行一個更新任務,這個任務所持有的優(yōu)先級

  •  調(diào)度優(yōu)先級:Scheduler依據(jù)React更新任務生成一個調(diào)度任務,這個調(diào)度任務所持有的優(yōu)先級

前三者屬于React的優(yōu)先級機制,第四個屬于Scheduler的優(yōu)先級機制,Scheduler內(nèi)部有自己的優(yōu)先級機制,雖然與React有所區(qū)別,但等級的劃分基本一致。下面我們從事件優(yōu)先級開始說起。

優(yōu)先級的起點:事件優(yōu)先級

React按照事件的緊急程度,把它們劃分成三個等級:

  •  離散事件(DiscreteEvent):click、keydown、focusin等,這些事件的觸發(fā)不是連續(xù)的,優(yōu)先級為0。

  •  用戶阻塞事件(UserBlockingEvent):drag、scroll、mouseover等,特點是連續(xù)觸發(fā),阻塞渲染,優(yōu)先級為1。

  •  連續(xù)事件(ContinuousEvent):canplay、error、audio標簽的timeupdate和canplay,優(yōu)先級最高,為2。

如何理解React中的優(yōu)先級

事件優(yōu)先級的Map

派發(fā)事件優(yōu)先級

事件優(yōu)先級是在注冊階段被確定的,在向root上注冊事件時,會根據(jù)事件的類別,創(chuàng)建不同優(yōu)先級的事件監(jiān)聽(listener),最終將它綁定到root上去。

let listener = createEventListenerWrapperWithPriority(      targetContainer,      domEventName,      eventSystemFlags,      listenerPriority,    );

createEventListenerWrapperWithPriority函數(shù)的名字已經(jīng)把它做的事情交代得八九不離十了。它會首先根據(jù)事件的名稱去找對應的事件優(yōu)先級,然后依據(jù)優(yōu)先級返回不同的事件監(jiān)聽函數(shù)。

export function createEventListenerWrapperWithPriority(    targetContainer: EventTarget,    domEventName: DOMEventName,    eventSystemFlags: EventSystemFlags,    priority?: EventPriority, ): Function {    const eventPriority =      priority === undefined        ? getEventPriorityForPluginSystem(domEventName)        : priority;    let listenerWrapper;    switch (eventPriority) {      case DiscreteEvent:        listenerWrapper = dispatchDiscreteEvent;        break;      case UserBlockingEvent:        listenerWrapper = dispatchUserBlockingUpdate;        break;      case ContinuousEvent:      default:        listenerWrapper = dispatchEvent;        break;    }    return listenerWrapper.bind(      null,      domEventName,      eventSystemFlags,      targetContainer,    );  }

最終綁定到root上的事件監(jiān)聽其實是dispatchDiscreteEvent、dispatchUserBlockingUpdate、dispatchEvent這三個中的一個。它們做的事情都是一樣的,以各自的事件優(yōu)先級去執(zhí)行真正的事件處理函數(shù)。

比如:dispatchDiscreteEvent和dispatchUserBlockingUpdate最終都會以UserBlockingEvent的事件級別去執(zhí)行事件處理函數(shù)。

以某種優(yōu)先級去執(zhí)行事件處理函數(shù)其實要借助Scheduler中提供的runWithPriority函數(shù)來實現(xiàn):

function dispatchUserBlockingUpdate(    domEventName,    eventSystemFlags,    container,    nativeEvent,  ) {    ...    runWithPriority(      UserBlockingPriority,      dispatchEvent.bind(        null,        domEventName,        eventSystemFlags,        container,        nativeEvent,      ),    );    ...  }

這么做可以將事件優(yōu)先級記錄到Scheduler中,相當于告訴Scheduler:你幫我記錄一下當前事件派發(fā)的優(yōu)先級,等React那邊創(chuàng)建更新對象(即update)計算更新優(yōu)先級時直接從你這拿就好了。

function unstable_runWithPriority(priorityLevel, eventHandler) {    switch (priorityLevel) {      case ImmediatePriority:      case UserBlockingPriority:      case NormalPriority:      case LowPriority:      case IdlePriority:        break;      default:        priorityLevel = NormalPriority;    }    var previousPriorityLevel = currentPriorityLevel;    // 記錄優(yōu)先級到Scheduler內(nèi)部的變量里    currentPriorityLevel = priorityLevel;    try {      return eventHandler();    } finally {      currentPriorityLevel = previousPriorityLevel;    }  }

更新優(yōu)先級

以setState為例,事件的執(zhí)行會導致setState執(zhí)行,而setState本質(zhì)上是調(diào)用enqueueSetState,生成一個update對象,這時候會計算它的更新優(yōu)先級,即update.lane:

const classComponentUpdater = {    enqueueSetState(inst, payload, callback) {      ...      // 依據(jù)事件優(yōu)先級創(chuàng)建update的優(yōu)先級      const lane = requestUpdateLane(fiber, suspenseConfig);      const update = createUpdate(eventTime, lane, suspenseConfig);      update.payload = payload;      enqueueUpdate(fiber, update);      // 開始調(diào)度      scheduleUpdateOnFiber(fiber, lane, eventTime);      ...    },  };

重點關注requestUpdateLane,它首先找出Scheduler中記錄的優(yōu)先級:schedulerPriority,然后計算更新優(yōu)先級:lane,具體的計算過程在findUpdateLane函數(shù)中,計算過程是一個從高到低依次占用空閑位的操作,具體的代碼在這里 ,這里就先不詳細展開。

export function requestUpdateLane(    fiber: Fiber,    suspenseConfig: SuspenseConfig | null,  ): Lane {    ...    // 根據(jù)記錄下的事件優(yōu)先級,獲取任務調(diào)度優(yōu)先級    const schedulerPriority = getCurrentPriorityLevel();    let lane;    if (      (executionContext & DiscreteEventContext) !== NoContext &&      schedulerPriority === UserBlockingSchedulerPriority    ) {      // 如果事件優(yōu)先級是用戶阻塞級別,則直接用InputDiscreteLanePriority去計算更新優(yōu)先級      lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes);    } else {      // 依據(jù)事件的優(yōu)先級去計算schedulerLanePriority      const schedulerLanePriority = schedulerPriorityToLanePriority(        schedulerPriority,      );      ...      // 根據(jù)事件優(yōu)先級計算得來的schedulerLanePriority,去計算更新優(yōu)先級      lane = findUpdateLane(schedulerLanePriority, currentEventWipLanes);    }    return lane;  }

getCurrentPriorityLevel負責讀取記錄在Scheduler中的優(yōu)先級:

function unstable_getCurrentPriorityLevel() {    return currentPriorityLevel;  }

update對象創(chuàng)建完成后意味著需要對頁面進行更新,會調(diào)用scheduleUpdateOnFiber進入調(diào)度,而真正開始調(diào)度之前會計算本次產(chǎn)生的更新任務的任務優(yōu)先級,目的是與已有任務的任務優(yōu)先級去做比較,便于做出多任務的調(diào)度決策。

調(diào)度決策的邏輯在ensureRootIsScheduled 函數(shù)中,這是一個非常重要的函數(shù),控制著React任務進入Scheduler的大門。

任務優(yōu)先級

一個update會被一個React的更新任務執(zhí)行掉,任務優(yōu)先級被用來區(qū)分多個更新任務的緊急程度,它由更新優(yōu)先級計算而來,舉例來說:

假設產(chǎn)生一前一后兩個update,它們持有各自的更新優(yōu)先級,也會被各自的更新任務執(zhí)行。經(jīng)過優(yōu)先級計算,如果后者的任務優(yōu)先級高于前者的任務優(yōu)先級,那么會讓Scheduler取消前者的任務調(diào)度;如果后者的任務優(yōu)先級等于前者的任務優(yōu)先級,后者不會導致前者被取消,而是會復用前者的更新任務,將兩個同等優(yōu)先級的更新收斂到一次任務中;如果后者的任務優(yōu)先級低于前者的任務優(yōu)先級,同樣不會導致前者的任務被取消,而是在前者更新完成后,再次用Scheduler對后者發(fā)起一次任務調(diào)度。

這是任務優(yōu)先級存在的意義,保證高優(yōu)先級任務及時響應,收斂同等優(yōu)先級的任務調(diào)度。

任務優(yōu)先級在即將調(diào)度的時候去計算,代碼在ensureRootIsScheduled函數(shù)中:

function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {    ...    // 獲取nextLanes,順便計算任務優(yōu)先級    const nextLanes = getNextLanes(      root,      root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes,    );    // 獲取上面計算得出的任務優(yōu)先級    const newCallbackPriority = returnNextLanesPriority();    ...  }

通過調(diào)用getNextLanes去計算在本次更新中應該處理的這批lanes(nextLanes),getNextLanes會調(diào)用getHighestPriorityLanes去計算任務優(yōu)先級。任務優(yōu)先級計算的原理是這樣:更新優(yōu)先級(update的lane),它會被并入root.pendingLanes,root.pendingLanes經(jīng)過getNextLanes處理后,挑出那些應該處理的lanes,傳入getHighestPriorityLanes,根據(jù)nextLanes找出這些lanes的優(yōu)先級作為任務優(yōu)先級。

function getHighestPriorityLanes(lanes: Lanes | Lane): Lanes {  ...    // 都是這種比較賦值的過程,這里只保留兩個以做簡要說明    const inputDiscreteLanes = InputDiscreteLanes & lanes;    if (inputDiscreteLanes !== NoLanes) {      return_highestLanePriority = InputDiscreteLanePriority;      return inputDiscreteLanes;    }    if ((lanes & InputContinuousHydrationLane) !== NoLanes) {     return_highestLanePriority = InputContinuousHydrationLanePriority;      return InputContinuousHydrationLane;    }    ...    return lanes;  }

getHighestPriorityLanes的源碼在這里,getNextLanes的源碼在這里

return_highestLanePriority就是任務優(yōu)先級,它有如下這些值,值越大,優(yōu)先級越高,暫時只理解任務優(yōu)先級的作用即可。

export const SyncLanePriority: LanePriority = 17;  export const SyncBatchedLanePriority: LanePriority = 16;  const InputDiscreteHydrationLanePriority: LanePriority = 15;  export const InputDiscreteLanePriority: LanePriority = 14;  const InputContinuousHydrationLanePriority: LanePriority = 13;  export const InputContinuousLanePriority: LanePriority = 12;  const DefaultHydrationLanePriority: LanePriority = 11;  export const DefaultLanePriority: LanePriority = 10;  const TransitionShortHydrationLanePriority: LanePriority = 9;  export const TransitionShortLanePriority: LanePriority = 8;  const TransitionLongHydrationLanePriority: LanePriority = 7;  export const TransitionLongLanePriority: LanePriority = 6;  const RetryLanePriority: LanePriority = 5;  const SelectiveHydrationLanePriority: LanePriority = 4;  const IdleHydrationLanePriority: LanePriority = 3;  const IdleLanePriority: LanePriority = 2;  const OffscreenLanePriority: LanePriority = 1;  export const NoLanePriority: LanePriority = 0;

如果已經(jīng)存在一個更新任務,ensureRootIsScheduled會在獲取到新任務的任務優(yōu)先級之后,去和舊任務的任務優(yōu)先級去比較,從而做出是否需要重新發(fā)起調(diào)度的決定,若需要發(fā)起調(diào)度,那么會去計算調(diào)度優(yōu)先級。

調(diào)度優(yōu)先級

一旦任務被調(diào)度,那么它就會進入Scheduler,在Scheduler中,這個任務會被包裝一下,生成一個屬于Scheduler自己的task,這個task持有的優(yōu)先級就是調(diào)度優(yōu)先級。

它有什么作用呢?在Scheduler中,分別用過期任務隊列和未過期任務的隊列去管理它內(nèi)部的task,過期任務的隊列中的task根據(jù)過期時間去排序,最早過期的排在前面,便于被最先處理。而過期時間是由調(diào)度優(yōu)先級計算得出的,不同的調(diào)度優(yōu)先級對應的過期時間不同。

調(diào)度優(yōu)先級由任務優(yōu)先級計算得出,在ensureRootIsScheduled更新真正讓Scheduler發(fā)起調(diào)度的時候,會去計算調(diào)度優(yōu)先級。

function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {      ...      // 根據(jù)任務優(yōu)先級獲取Scheduler的調(diào)度優(yōu)先級      const schedulerPriorityLevel = lanePriorityToSchedulerPriority(        newCallbackPriority,      );      // 計算出調(diào)度優(yōu)先級之后,開始讓Scheduler調(diào)度React的更新任務      newCallbackNode = scheduleCallback(        schedulerPriorityLevel,        performConcurrentWorkOnRoot.bind(null, root),      );      ... }

lanePriorityToSchedulerPriority計算調(diào)度優(yōu)先級的過程是根據(jù)任務優(yōu)先級找出對應的調(diào)度優(yōu)先級。

export function lanePriorityToSchedulerPriority(    lanePriority: LanePriority,  ): ReactPriorityLevel {    switch (lanePriority) {      case SyncLanePriority:      case SyncBatchedLanePriority:        return ImmediateSchedulerPriority;      case InputDiscreteHydrationLanePriority:      case InputDiscreteLanePriority:      case InputContinuousHydrationLanePriority:      case InputContinuousLanePriority:        return UserBlockingSchedulerPriority;      case DefaultHydrationLanePriority:      case DefaultLanePriority:      case TransitionShortHydrationLanePriority:      case TransitionShortLanePriority:      case TransitionLongHydrationLanePriority:      case TransitionLongLanePriority:      case SelectiveHydrationLanePriority:      case RetryLanePriority:        return NormalSchedulerPriority;      case IdleHydrationLanePriority:      case IdleLanePriority:     case OffscreenLanePriority:        return IdleSchedulerPriority;      case NoLanePriority:        return NoSchedulerPriority;      default:        invariant(          false,          'Invalid update priority: %s. This is a bug in React.',          lanePriority,        );    }  }

感謝各位的閱讀,以上就是“如何理解React中的優(yōu)先級”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對如何理解React中的優(yōu)先級這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關知識點的文章,歡迎關注!


當前文章:如何理解React中的優(yōu)先級
本文URL:http://weahome.cn/article/jedopi.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部