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

React利用scheduler思想實現(xiàn)任務(wù)的打斷與恢復(fù)

 更新時間:2024年03月14日 14:21:23   作者:程序員小洛  
這篇文章主要為大家詳細介紹了React如何利用scheduler思想實現(xiàn)任務(wù)的打斷與恢復(fù),文中的示例代碼講解詳細,感興趣的小伙伴可以參考一下

前言

react 16.8版本引入了fiber架構(gòu),在fiber架構(gòu)的支持下,實現(xiàn)了并發(fā)渲染。

在16.8版本以前,在state改變后,經(jīng)過一系列的流程,最終會進入diff,在diff的時候,會采用DFS進行遍歷虛擬dom樹,這個遍歷過程是一口氣完成的,當(dāng)我們的應(yīng)用很復(fù)雜,元素比較多的時候,diff的過程往往會花費很長的時間,主線程此時正在進行diif比較,如果diff事件超過16.6ms,會造成瀏覽器掉幀,如果時間很長,會造成頁面卡頓。

在react18版本,默認(rèn)開啟了并發(fā)模式,開發(fā)者可以使用useTransition hook手動開并發(fā)模式,在并發(fā)模式下,diff過程是可中斷的,如果diff時間超過5ms,那么React會中斷此次diff,會交出主線程的使用權(quán),從而讓瀏覽器去渲染,當(dāng)有空閑的時間的時候,會利用時間循環(huán)機制恢復(fù)diif,從而提高大型應(yīng)用的用戶體驗。并發(fā)模式下任務(wù)的打斷與恢復(fù)機制是scheduler提供的,我們今天將探討下,如何利用React scheduler打斷一個耗時任務(wù),例如從0累加到2000萬。

scheduler

從0累加到2000萬

const work = () => {
  for(let currentIndex = 0; currentIndex <  totalCount; currentIndex++) {
    sum += currentIndex
  }
}

火焰圖

我們看上面的火焰圖,這個任務(wù)執(zhí)行了近100ms,左右,超過了瀏覽器的一幀16.6ms,當(dāng)一個任務(wù)執(zhí)行時間超過50ms時,瀏覽器會任務(wù)這個任務(wù)時長任務(wù),超過50ms的部分,火焰圖會標(biāo)記為紅色。

既然同步遍歷會造成瀏覽器掉幀,那么我們有什么辦法做到不讓瀏覽器掉幀呢?答案就是將這2000萬個累加操作分成很小的task,然后讓task作為一個工作單元去執(zhí)行,當(dāng)執(zhí)行到一定的數(shù)量的時候,如果運行時間超過了我們規(guī)定的時間,那么我們中斷這個任務(wù),在中斷的時候判斷下還有沒有任務(wù)要執(zhí)行,如果有任務(wù)要執(zhí)行,那么我們將這個任務(wù)執(zhí)行函數(shù)放入事件循環(huán)中,等下一次事件循環(huán)的時候,取出來執(zhí)行這個任務(wù)。

如何讓for循環(huán)中斷呢? 我們只需要在遍歷的時候判斷當(dāng)前的索引和數(shù)據(jù)總數(shù)以及抽象出一個方法,判斷應(yīng)不應(yīng)該終止(比如:我規(guī)定讓task累計運行5ms,當(dāng)5ms用完的時候,就應(yīng)該終止)。

const getCurrentTime = () => Date.now();

// 調(diào)度應(yīng)該被中斷嗎
function shouldYieldToHost() {
  const timeElapsed = getCurrentTime() - startTime;
  // 如果當(dāng)前時間減去開始時間小于 5ms, 那么繼續(xù)調(diào)度
  if (timeElapsed < 5) {
    return false;
  }
  return true;
}

const work = () => {
  for(let currentIndex = 0; currentIndex <  totalCount && !shouldYieldToHost(); currentIndex++) {
    sum += currentIndex
  }
}

如何判斷有沒有任務(wù)需要恢復(fù)呢? 我們將work函數(shù)放在workloop函數(shù)中去執(zhí)行,當(dāng)work函數(shù)終止的時候,調(diào)用?;氐?code>workloop函數(shù)時,判斷currentIndex < totalCount,如果小于,那么我們 reutrn true,告訴調(diào)用workloop的函數(shù)還有任務(wù)需要執(zhí)行,需要將任務(wù)執(zhí)行函數(shù)放到異步任務(wù)中,等下一次事件循環(huán)的時候取出來執(zhí)行。

const flushWork = () => {
  return workLoop()
}

const workLoop = () => {
  while(true) {
      try {
        work()
      } catch (error) {
      }finally {
        if(currentIndex < totalCount) {
          return true
        } else {
          return false
        }
      }
  }
}

任務(wù)恢復(fù)機制,利用事件循環(huán)原理

const performWorkUntilDeadline = () => {
    const currentTime = getCurrentTime();
    startTime = currentTime;
    const hasTimeRemaining = true; // 有剩余時間

    let hasMoreWork = true;
    try {
      // 這里執(zhí)行的函數(shù)就是 flushWork,flushWork 如果返回一個 true 那么表示還有任務(wù)
      // 這里是 workLoop 循環(huán)里 return 的, 如果 return true, 那么表示還有剩余的任務(wù),只是時間用完了,被中斷了
       hasMoreWork = flushWork();
    } finally {
      //如果還有剩余任務(wù),調(diào)用schedulePerformWorkUntilDeadline將performWorkUntilDeadline 放入到異步任務(wù)里,等下一次事件循環(huán)被調(diào)用。
      if (hasMoreWork) {
        schedulePerformWorkUntilDeadline();
      } else {
      }
    }
  


let schedulePerformWorkUntilDeadline;
// react 中調(diào)度的優(yōu)先級  setImmediate > MessageChannel > setTimeout
if (typeof localSetImmediate === 'function') {
  schedulePerformWorkUntilDeadline = () => {
    localSetImmediate(performWorkUntilDeadline);
  };
} else if (typeof MessageChannel !== 'undefined') {
  const channel = new MessageChannel();
  const port = channel.port2;
  channel.port1.onmessage = performWorkUntilDeadline;
  schedulePerformWorkUntilDeadline = () => {
    port.postMessage(null);
  };
} else {
  schedulePerformWorkUntilDeadline = () => {
    localSetTimeout(performWorkUntilDeadline, 0);
  };
}

完整實現(xiàn)代碼

const localSetTimeout = typeof setTimeout === 'function' ? setTimeout : null;
const localClearTimeout =
  typeof clearTimeout === 'function' ? clearTimeout : null;
const localSetImmediate =
  typeof setImmediate !== 'undefined' ? setImmediate : null; 


let startTime; // 記錄開始時間
let sum = 0
const currentIndex = 0;  // 當(dāng)前遍歷的索引
const totalCount = 20000000  

const getCurrentTime = () => Date.now();

// 調(diào)度應(yīng)該被中斷嗎
function shouldYieldToHost() {
  const timeElapsed = getCurrentTime() - startTime;
  // 如果當(dāng)前時間減去開始時間小于 5ms, 那么繼續(xù)調(diào)度
  if (timeElapsed < 5) {
    return false;
  }
  return true;
}

const performWorkUntilDeadline = () => {
    const currentTime = getCurrentTime();
    startTime = currentTime;
    const hasTimeRemaining = true; // 有剩余時間

    let hasMoreWork = true;
    try {
      // 這里執(zhí)行的函數(shù)就是 flushWork,flushWork 如果返回一個 true 那么表示還有任務(wù)
      // 這里的 是 workLoop 循環(huán)里 return 的, 如果 return true, 那么表示還有剩余的任務(wù),只是時間用完了,被中斷了
       hasMoreWork = flushWork();
    } finally {
      if (hasMoreWork) {
        schedulePerformWorkUntilDeadline();
      } else {
      }
    }
  
};

let schedulePerformWorkUntilDeadline;
// react 中調(diào)度的優(yōu)先級  setImmediate > MessageChannel > setTimeout
if (typeof localSetImmediate === 'function') {
  schedulePerformWorkUntilDeadline = () => {
    localSetImmediate(performWorkUntilDeadline);
  };
} else if (typeof MessageChannel !== 'undefined') {
  const channel = new MessageChannel();
  const port = channel.port2;
  channel.port1.onmessage = performWorkUntilDeadline;
  schedulePerformWorkUntilDeadline = () => {
    port.postMessage(null);
  };
} else {
  schedulePerformWorkUntilDeadline = () => {
    localSetTimeout(performWorkUntilDeadline, 0);
  };
}

const flushWork = () => {
  return workLoop()
}

const workLoop = () => {
  while(true) {
      try {
        work()
      } catch (error) {
      }finally {
        if(currentIndex < totalCount) {
          return true
        } else {
          return false
        }
      }
  }
}

const work = () => {
  for(let currentIndex = 0; currentIndex <  totalCount && !shouldYieldToHost(); currentIndex++) {
    sum += currentIndex
  }
}

performWorkUntilDeadline()

火焰圖

我們可以看到,上面執(zhí)行近100ms的任務(wù)被分成了很多很多小任務(wù),其中每個小任務(wù)執(zhí)行的時間是5ms左右。這樣我們就完成了利用react scheduler實現(xiàn)任務(wù)的打斷與恢復(fù)機制。

以上就是React利用scheduler思想實現(xiàn)任務(wù)的打斷與恢復(fù)的詳細內(nèi)容,更多關(guān)于React scheduler任務(wù)的打斷與恢復(fù)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解React Angular Vue三大前端技術(shù)

    詳解React Angular Vue三大前端技術(shù)

    當(dāng)前世界中,技術(shù)發(fā)展非常迅速并且變化迅速,開發(fā)者需要更多的開發(fā)工具來解決不同的問題。本文就對于當(dāng)下主流的前端開發(fā)技術(shù)React、Vue、Angular這三個框架做個相對詳盡的探究,目的是為了解開這些前端技術(shù)的面紗,看看各自的廬山真面目。
    2021-05-05
  • React中g(shù)etDefaultProps的使用小結(jié)

    React中g(shù)etDefaultProps的使用小結(jié)

    React中的getDefaultProps功能允許開發(fā)者為類組件定義默認(rèn)屬性,提高組件的靈活性和容錯性,本文介紹了getDefaultProps的作用、語法以及最佳實踐,并探討了其他替代方案,如函數(shù)組件中的默認(rèn)參數(shù)、高階組件和ContextAPI等,理解這些概念有助于提升代碼的可維護性和用戶體驗
    2024-09-09
  • React中使用Vditor自定義圖片詳解

    React中使用Vditor自定義圖片詳解

    這篇文章主要介紹了React中使用Vditor自定義圖片詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • React如何自定義輪播圖Carousel組件

    React如何自定義輪播圖Carousel組件

    這篇文章主要介紹了React如何自定義輪播圖Carousel組件問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • React狀態(tài)提升案例介紹

    React狀態(tài)提升案例介紹

    這篇文章主要介紹了React狀態(tài)提升案例,所謂 狀態(tài)提升 就是將各個子組件的 公共state 提升到它們的父組件進行統(tǒng)一存儲、處理,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-04-04
  • React和Vue實現(xiàn)文件下載進度條

    React和Vue實現(xiàn)文件下載進度條

    本文主要介紹了React和Vue實現(xiàn)文件下載進度條,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • React中設(shè)置樣式style方式

    React中設(shè)置樣式style方式

    這篇文章主要介紹了React中設(shè)置樣式style方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • React Router 中實現(xiàn)嵌套路由和動態(tài)路由的示例

    React Router 中實現(xiàn)嵌套路由和動態(tài)路由的示例

    React Router 是一個非常強大和靈活的路由庫,它為 React 應(yīng)用程序提供了豐富的導(dǎo)航和 URL 管理功能,能夠幫助我們構(gòu)建復(fù)雜的單頁應(yīng)用和多頁應(yīng)用,這篇文章主要介紹了React Router 中如何實現(xiàn)嵌套路由和動態(tài)路由,需要的朋友可以參考下
    2023-05-05
  • React組件中的this的具體使用

    React組件中的this的具體使用

    這篇文章主要介紹了React組件中的this的具體使用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • React?Hook?Form?優(yōu)雅處理表單使用指南

    React?Hook?Form?優(yōu)雅處理表單使用指南

    這篇文章主要為大家介紹了React?Hook?Form?優(yōu)雅處理表單使用指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03

最新評論