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

JavaScript通過時(shí)間分片解決頁面卡頓的方法介紹

 更新時(shí)間:2025年08月31日 10:01:36   作者:輕語呢喃  
在前端開發(fā)中,我們時(shí)常會(huì)遇到需要處理大量數(shù)據(jù)渲染的場景,往往會(huì)導(dǎo)致頁面卡頓,時(shí)間分片(Time Slicing) ?則是解決這一問題的核心思想,下面就跟隨小編一起來了解下吧

在前端開發(fā)中,我們時(shí)常會(huì)遇到需要處理大量數(shù)據(jù)渲染的場景 —— 比如一次性插入 10000 條甚至更多數(shù)據(jù)到頁面中。采用 “暴力 破解” 的方式直接同步執(zhí)行,往往會(huì)導(dǎo)致頁面卡頓、白屏,嚴(yán)重影響用戶體驗(yàn)。

時(shí)間分片(Time Slicing)  則是解決這一問題的核心思想,它通過 “拆分任務(wù) + 異步調(diào)度” 的方式,讓 JS 執(zhí)行與頁面渲染互不阻塞,實(shí)現(xiàn)流暢的數(shù)據(jù)處理與展示。

一、問題:為什么大量數(shù)據(jù)直接渲染會(huì)卡頓

要理解時(shí)間分片的價(jià)值,首先我們要從瀏覽器的Event Loop(事件循環(huán))  機(jī)制入手。

眾所周知,瀏覽器的 JS 線程與渲染線程是 “互斥” 的 —— 也就是說,當(dāng) JS 線程在執(zhí)行同步代碼時(shí),渲染線程會(huì)被阻塞,導(dǎo)致無法更新頁面,只有當(dāng) JS 線程空閑時(shí),渲染線程才會(huì)執(zhí)行頁面重繪。

1.1 暴力 破解的困境:同步執(zhí)行的問題

為了讓大家更好的感受到普通方法和時(shí)間分片的區(qū)別,現(xiàn)在,我將先展示最直接的暴力 破解法,其核心邏輯就是通過for循環(huán)同步創(chuàng)建 10000 個(gè)li元素并插入頁面:

<ul id="container"></ul>
<script>
  let now = Date.now();
  const total = 100000;
  let ul = document.getElementById('container');
  // 同步循環(huán)創(chuàng)建并插入元素
  for(let i = 0; i < total; i++){
    let li = document.createElement('li');
    li.innerText = Math.random()*total;
    ul.appendChild(li);
  }
  console.log('JS運(yùn)行時(shí)間', Date.now() - now); // 看似JS執(zhí)行快
  setTimeout(()=>{
    console.log('總運(yùn)行時(shí)間', Date.now() - now); // 實(shí)際總耗時(shí)遠(yuǎn)更長
  },0);
</script>

這是運(yùn)行結(jié)束后的運(yùn)行時(shí)間:

從這里可以看出,暴力 破解法問題如下:

  • JS 線程阻塞:100000 次createElement、appendChild是同步任務(wù),會(huì)占據(jù) JS 線程較長時(shí)間(即使 JS 本身執(zhí)行耗時(shí)短,DOM 操作的開銷也會(huì)累積);
  • 渲染被推遲:在 JS 同步任務(wù)執(zhí)行期間,渲染線程完全被阻塞,頁面無法更新,用戶會(huì)看到 “白屏” 或 “卡頓”,直到所有 JS 任務(wù)結(jié)束后,渲染線程才會(huì)一次性完成所有元素的繪制;
  • 用戶體驗(yàn)差:若數(shù)據(jù)量更大(比如 100 萬條),那么很可能導(dǎo)致瀏覽器出現(xiàn) “無響應(yīng)” 。

二、時(shí)間分片思想

時(shí)間分片的本質(zhì)是 **“化整為零” —— 將原本需要一次性完成的大量任務(wù)(如 100000 條數(shù)據(jù)渲染),拆分成多個(gè)小批次任務(wù)(如每次渲染 10 條),并通過異步調(diào)度機(jī)制 **(如setTimeout、requestAnimationFrame)讓這些小任務(wù)在 JS 線程空閑時(shí)執(zhí)行。

其核心邏輯符合 Event Loop 的調(diào)度規(guī)則:

  • 執(zhí)行一小批任務(wù)(如渲染 10 條數(shù)據(jù)),耗時(shí)極短(通常 < 16ms,遠(yuǎn)小于屏幕刷新周期);
  • 釋放 JS 線程,讓渲染線程執(zhí)行頁面更新(此時(shí)用戶能看到已渲染的部分?jǐn)?shù)據(jù),無白屏);
  • 等待下一次異步調(diào)度時(shí)機(jī),重復(fù)執(zhí)行下一批任務(wù),直到所有數(shù)據(jù)處理完成。

通過這種方式,JS 執(zhí)行與頁面渲染交替進(jìn)行,既完成了大量數(shù)據(jù)處理,又保證了頁面的流暢性。

三、時(shí)間分片的實(shí)現(xiàn)方式

3.1 基礎(chǔ)實(shí)現(xiàn):基于 setTimeout 的異步調(diào)度

setTimeout是最基礎(chǔ)的異步調(diào)度 API,它能將任務(wù)推入 “宏任務(wù)隊(duì)列”,待當(dāng)前同步任務(wù)執(zhí)行完畢、微任務(wù)隊(duì)列清空后,再等待指定時(shí)間(此處設(shè)為 0ms,即盡快執(zhí)行)執(zhí)行。

代碼示例:

<ul id="container"></ul>
<script>
  let ul = document.getElementById('container');
  const total = 100000; // 總數(shù)據(jù)量
  const once = 50; // 每次渲染50條(批次大小,可調(diào)整)
  let index = 0; // 當(dāng)前渲染的起始索引

  // 遞歸執(zhí)行分片任務(wù)
  const loop = (curTotal, curIndex) => {
    // 終止條件:剩余數(shù)據(jù)為0時(shí)停止
    if (curTotal <= 0) return false;

    // 計(jì)算當(dāng)前批次需渲染的數(shù)量(避免最后一批不足10條)
    const pageCount = Math.min(curTotal, once);

    // 異步執(zhí)行當(dāng)前批次渲染
    setTimeout(() => {
      for (let i = 0; i < pageCount; i++) {
        const li = document.createElement('li');
        li.innerText = `${curIndex + i}: ${Math.random() * total}`;
        ul.appendChild(li);
      }
      // 遞歸執(zhí)行下一批:剩余數(shù)據(jù)量=當(dāng)前總量-本批數(shù)量,起始索引=當(dāng)前索引+本批數(shù)量
      loop(curTotal - pageCount, curIndex + pageCount);
    }, 0);
  };

  // 啟動(dòng)分片渲染
  loop(total, index);
</script>

核心邏輯解析:

  • 批次大?。╫nce) :設(shè)為 50 是權(quán)衡 “渲染效率” 與 “流暢度” 的結(jié)果 —— 批次太小會(huì)增加異步調(diào)度次數(shù),批次太大仍可能阻塞,這個(gè)數(shù)據(jù)可根據(jù)實(shí)際數(shù)據(jù)量調(diào)整。
  • 遞歸終止:當(dāng)curTotal(剩余數(shù)據(jù)量)≤0 時(shí),停止遞歸,避免無限調(diào)用;
  • 異步調(diào)度setTimeout(fn, 0)確保當(dāng)前批次的 DOM 操作在 “下一次宏任務(wù)” 中執(zhí)行,此時(shí) JS 線程會(huì)先釋放,讓渲染線程更新已完成的部分。

不足:可能存在 “輕微白屏”

setTimeout的調(diào)度時(shí)機(jī)由 JS 引擎決定,不一定與瀏覽器的 “屏幕刷新周期”(通常為 60Hz,即每 16.6ms 刷新一次)同步。

若宏任務(wù)執(zhí)行時(shí)機(jī)與渲染時(shí)機(jī)錯(cuò)位,在我們拖動(dòng)進(jìn)度條時(shí),可能導(dǎo)致短暫的 “白屏”(雖比同步執(zhí)行好很多,但體驗(yàn)仍有優(yōu)化空間)。

3.2 優(yōu)化實(shí)現(xiàn):基于 requestAnimationFrame 的渲染同步

為解決setTimeout的 “時(shí)機(jī)錯(cuò)位” 問題,可使用瀏覽器原生 API——requestAnimationFrame(rAF) 。它的核心優(yōu)勢是:確?;卣{(diào)函數(shù)在 “屏幕每一次刷新前” 執(zhí)行,與渲染周期完全同步,不會(huì)丟幀,徹底解決白屏問題。

實(shí)現(xiàn)代碼(文檔示例):

<ul id="container"></ul>
<script>
  let ul = document.getElementById('container');
  const total = 100000;
  const once = 50;
  let index = 0;

  const loop = (curTotal, curIndex) => {
    if (curTotal <= 0) return false;

    const pageCount = Math.min(curTotal, once);

    // 用rAF替代setTimeout,與屏幕刷新同步
    requestAnimationFrame(() => {
      for (let i = 0; i < pageCount; i++) {
        const li = document.createElement('li');
        li.innerText = `${curIndex + i}: ${(Math.random() * total).toFixed(2)}`;
        ul.appendChild(li);
      }
      loop(curTotal - pageCount, curIndex + pageCount);
    });
  };

  loop(total, index);
</script>

核心優(yōu)勢:

  • 渲染同步:rAF 的回調(diào)會(huì)在瀏覽器準(zhǔn)備好重繪時(shí)觸發(fā)(約每 16.6ms 一次),確保當(dāng)前批次的 DOM 操作完成后,渲染線程能立即更新頁面,用戶看到的是 “逐步流暢加載”,無任何白屏;
  • 性能友好:若瀏覽器標(biāo)簽頁處于 “后臺(tái)”,rAF 會(huì)自動(dòng)暫停,避免浪費(fèi) CPU 資源(setTimeout仍會(huì)執(zhí)行)。

適用場景:

對(duì)渲染流暢度要求高的場景,如長列表渲染、大數(shù)據(jù)表格展示等。

四、兩種實(shí)現(xiàn)方式的對(duì)比

特性setTimeout 實(shí)現(xiàn)requestAnimationFrame 實(shí)現(xiàn)
調(diào)度時(shí)機(jī)宏任務(wù)隊(duì)列,時(shí)機(jī)不固定與屏幕刷新同步(≈16.6ms / 次)
白屏問題可能存在輕微白屏無白屏,渲染流暢
后臺(tái)運(yùn)行仍會(huì)執(zhí)行,消耗 CPU后臺(tái)暫停,節(jié)省資源
兼容性所有瀏覽器支持IE9 + 支持(現(xiàn)代瀏覽器均兼容)
適用場景對(duì)流暢度要求不高的簡單場景長列表、大數(shù)據(jù)渲染等核心場景

到此這篇關(guān)于JavaScript通過時(shí)間分片解決頁面卡頓的方法介紹的文章就介紹到這了,更多相關(guān)JavaScript時(shí)間分片內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JavaScript使用Promise實(shí)現(xiàn)分批處理接口請(qǐng)求

    JavaScript使用Promise實(shí)現(xiàn)分批處理接口請(qǐng)求

    當(dāng)我們在實(shí)際項(xiàng)目中遇到需要批量發(fā)起上百條接口請(qǐng)求怎么辦呢,本文就來為大家介紹一下JavaScript如何使用Promise實(shí)現(xiàn)分批處理接口請(qǐng)求,需要的小伙伴可以參考一下
    2023-11-11
  • uniapp實(shí)現(xiàn)上拉加載更多功能的全過程

    uniapp實(shí)現(xiàn)上拉加載更多功能的全過程

    我們在項(xiàng)目中經(jīng)常使用到上拉加載更多,下面這篇文章主要給大家介紹了關(guān)于uniapp實(shí)現(xiàn)上拉加載更多功能的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-10-10
  • Script標(biāo)簽與訪問HTML頁面詳解

    Script標(biāo)簽與訪問HTML頁面詳解

    本篇文章主要是對(duì)Script標(biāo)簽與訪問HTML頁面進(jìn)行了詳細(xì)的介紹,需要的朋友可以過來參考下,希望對(duì)大家有所幫助
    2014-01-01
  • JS實(shí)現(xiàn)圓形進(jìn)度條拖拽滑動(dòng)

    JS實(shí)現(xiàn)圓形進(jìn)度條拖拽滑動(dòng)

    這篇文章主要為大家詳細(xì)介紹了JS實(shí)現(xiàn)圓形進(jìn)度條拖拽滑動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • js判斷滾動(dòng)條是否已到頁面最底部或頂部實(shí)例

    js判斷滾動(dòng)條是否已到頁面最底部或頂部實(shí)例

    這篇文章主要介紹了js判斷滾動(dòng)條是否已到頁面最底部或頂部的原理與方法,以實(shí)例的形式詳細(xì)分析了js實(shí)現(xiàn)返回頂部功能所涉及的各種技巧,并對(duì)相關(guān)知識(shí)點(diǎn)進(jìn)行了總結(jié)歸納,需要的朋友可以參考下
    2014-11-11
  • 基于Bootstrap 3 JQuery及RegExp的表單驗(yàn)證功能

    基于Bootstrap 3 JQuery及RegExp的表單驗(yàn)證功能

    這篇文章主要介紹了基于Bootstrap 3 JQuery及RegExp的表單驗(yàn)證功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-02-02
  • JS實(shí)現(xiàn)針對(duì)給定時(shí)間的倒計(jì)時(shí)功能示例

    JS實(shí)現(xiàn)針對(duì)給定時(shí)間的倒計(jì)時(shí)功能示例

    這篇文章主要介紹了JS實(shí)現(xiàn)針對(duì)給定時(shí)間的倒計(jì)時(shí)功能,結(jié)合具體實(shí)例形式分析了javascript日期時(shí)間的正則判定與動(dòng)態(tài)運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下
    2017-04-04
  • JavaScript數(shù)組filter方法

    JavaScript數(shù)組filter方法

    filter()創(chuàng)建一個(gè)新的數(shù)組,新數(shù)組中的元素是通過檢查指定數(shù)組中符合條件的所有元素,這篇文章主要介紹了JavaScript數(shù)組filter方法,需要的朋友可以參考下
    2022-12-12
  • JavaScript組合設(shè)計(jì)模式--改進(jìn)引入案例分析

    JavaScript組合設(shè)計(jì)模式--改進(jìn)引入案例分析

    這篇文章主要介紹了JavaScript組合設(shè)模式改進(jìn)引入案例,結(jié)合實(shí)例形式分析了JavaScript組合設(shè)計(jì)模式特性改進(jìn)的引入示例相關(guān)操作技巧,需要的朋友可以參考下
    2020-05-05
  • 用JavaScript隱藏控件的方法

    用JavaScript隱藏控件的方法

    用JavaScript隱藏控件的方法有兩種,分別是通過設(shè)置控件的style的“display”和“visibility”屬性。
    2009-09-09

最新評(píng)論

吴堡县| 建瓯市| 虎林市| 阿拉善右旗| 宁夏| 黔江区| 鹿泉市| 长沙市| 兴文县| 黎平县| 壤塘县| 神农架林区| 思茅市| 金湖县| 阿克苏市| 丰原市| 阳春市| 彭山县| 黄浦区| 仁布县| 顺昌县| 银川市| 巩义市| 溧水县| 蓬安县| 南和县| 水城县| 曲阳县| 确山县| 兴义市| 天祝| 松江区| 潜江市| 奈曼旗| 望江县| 冕宁县| 麦盖提县| 苏尼特左旗| 宕昌县| 桓仁| 石城县|