国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

記錄--你敢信?比 setTimeout 還快 80 倍的定時(shí)器

這篇具有很好參考價(jià)值的文章主要介紹了記錄--你敢信?比 setTimeout 還快 80 倍的定時(shí)器。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

這里給大家分享我在網(wǎng)上總結(jié)出來(lái)的一些知識(shí),希望對(duì)大家有所幫助

記錄--你敢信?比 setTimeout 還快 80 倍的定時(shí)器

起因

很多人都知道,setTimeout是有最小延遲時(shí)間的,根據(jù)MDN 文檔 setTimeout:實(shí)際延時(shí)比設(shè)定值更久的原因:最小延遲時(shí)間中所說(shuō):

在瀏覽器中,setTimeout()/setInterval() 的每調(diào)用一次定時(shí)器的最小間隔是 4ms,這通常是由于函數(shù)嵌套導(dǎo)致(嵌套層級(jí)達(dá)到一定深度)。

在HTML Standard規(guī)范中也有提到更具體的:

Timers can be nested; after five such nested timers, however, the interval is forced to be at least four milliseconds.

簡(jiǎn)單來(lái)說(shuō),5 層以上的定時(shí)器嵌套會(huì)導(dǎo)致至少 4ms 的延遲。

用如下代碼做個(gè)測(cè)試:

let a = performance.now();
setTimeout(() => {
  let b = performance.now();
  console.log(b - a);
  setTimeout(() => {
    let c = performance.now();
    console.log(c - b);
    setTimeout(() => {
      let d = performance.now();
      console.log(d - c);
      setTimeout(() => {
        let e = performance.now();
        console.log(e - d);
        setTimeout(() => {
          let f = performance.now();
          console.log(f - e);
          setTimeout(() => {
            let g = performance.now();
            console.log(g - f);
          }, 0);
        }, 0);
      }, 0);
    }, 0);
  }, 0);
}, 0);

在瀏覽器中的打印結(jié)果大概是這樣的,和規(guī)范一致,第五次執(zhí)行的時(shí)候延遲來(lái)到了 4ms 以上。

?

記錄--你敢信?比 setTimeout 還快 80 倍的定時(shí)器

探索

假設(shè)就需要一個(gè)「立刻執(zhí)行」的定時(shí)器呢?有什么辦法繞過(guò)這個(gè) 4ms 的延遲嗎,在 MDN 文檔的角落里有一些線索:

如果想在瀏覽器中實(shí)現(xiàn) 0ms 延時(shí)的定時(shí)器,可以參考這里所說(shuō)的window.postMessage()

這篇文章里的作者給出了這樣一段代碼,用postMessage來(lái)實(shí)現(xiàn)真正 0 延遲的定時(shí)器:

(function () {
  var timeouts = [];
  var messageName = 'zero-timeout-message';

  // 保持 setTimeout 的形態(tài),只接受單個(gè)函數(shù)的參數(shù),延遲始終為 0。
  function setZeroTimeout(fn) {
    timeouts.push(fn);
    window.postMessage(messageName, '*');
  }

  function handleMessage(event) {
    if (event.source == window && event.data == messageName) {
      event.stopPropagation();
      if (timeouts.length > 0) {
        var fn = timeouts.shift();
        fn();
      }
    }
  }

  window.addEventListener('message', handleMessage, true);

  // 把 API 添加到 window 對(duì)象上
  window.setZeroTimeout = setZeroTimeout;
})();

由于postMessage的回調(diào)函數(shù)的執(zhí)行時(shí)機(jī)和setTimeout類似,都屬于宏任務(wù),所以可以簡(jiǎn)單利用postMessageaddEventListener('message')的消息通知組合,來(lái)實(shí)現(xiàn)模擬定時(shí)器的功能。

這樣,執(zhí)行時(shí)機(jī)類似,但是延遲更小的定時(shí)器就完成了。

再利用上面的嵌套定時(shí)器的例子來(lái)跑一下測(cè)試:

記錄--你敢信?比 setTimeout 還快 80 倍的定時(shí)器

全部在 0.1 ~ 0.3 毫秒級(jí)別,而且不會(huì)隨著嵌套層數(shù)的增多而增加延遲。

測(cè)試

從理論上來(lái)說(shuō),由于postMessage的實(shí)現(xiàn)沒(méi)有被瀏覽器引擎限制速度,一定是比 setTimeout 要快的。

設(shè)計(jì)一個(gè)實(shí)驗(yàn)方法,就是分別用postMessage版定時(shí)器和傳統(tǒng)定時(shí)器做一個(gè)遞歸執(zhí)行計(jì)數(shù)函數(shù)的操作,看看同樣計(jì)數(shù)到 100 分別需要花多少時(shí)間。

實(shí)驗(yàn)代碼:

function runtest() {
  var output = document.getElementById('output');
  var outputText = document.createTextNode('');
  output.appendChild(outputText);
  function printOutput(line) {
    outputText.data += line + '\n';
  }

  var i = 0;
  var startTime = Date.now();
  // 通過(guò)遞歸 setZeroTimeout 達(dá)到 100 計(jì)數(shù)
  // 達(dá)到 100 后切換成 setTimeout 來(lái)實(shí)驗(yàn)
  function test1() {
    if (++i == 100) {
      var endTime = Date.now();
      printOutput(
        '100 iterations of setZeroTimeout took ' +
        (endTime - startTime) +
        ' milliseconds.'
      );
      i = 0;
      startTime = Date.now();
      setTimeout(test2, 0);
    } else {
      setZeroTimeout(test1);
    }
  }

  setZeroTimeout(test1);

  // 通過(guò)遞歸 setTimeout 達(dá)到 100 計(jì)數(shù)
  function test2() {
    if (++i == 100) {
      var endTime = Date.now();
      printOutput(
        '100 iterations of setTimeout(0) took ' +
        (endTime - startTime) +
        ' milliseconds.'
      );
    } else {
      setTimeout(test2, 0);
    }
  }
}

實(shí)驗(yàn)代碼很簡(jiǎn)單,先通過(guò)setZeroTimeout也就是postMessage版本來(lái)遞歸計(jì)數(shù)到 100,然后切換成 setTimeout計(jì)數(shù)到 100。

直接放結(jié)論,這個(gè)差距不固定,在 mac 上用無(wú)痕模式排除插件等因素的干擾后,以計(jì)數(shù)到 100 為例,大概有 80 ~ 100 倍的時(shí)間差距。在硬件更好的臺(tái)式機(jī)上,甚至能到 200 倍以上。

記錄--你敢信?比 setTimeout 還快 80 倍的定時(shí)器

Performance 面板

只是看冷冰冰的數(shù)字還不夠過(guò)癮,打開(kāi) Performance 面板,看看更直觀的可視化界面中,postMessage版的定時(shí)器和setTimeout版的定時(shí)器是如何分布的。

記錄--你敢信?比 setTimeout 還快 80 倍的定時(shí)器

這張分布圖非常直觀的體現(xiàn)出了上面所說(shuō)的所有現(xiàn)象,左邊的postMessage版本的定時(shí)器分布非常密集,大概在 5ms 以內(nèi)就執(zhí)行完了所有的計(jì)數(shù)任務(wù)。

而右邊的setTimeout版本相比較下分布的就很稀疏了,而且通過(guò)上方的時(shí)間軸可以看出,前四次的執(zhí)行間隔大概在 1ms 左右,到了第五次就拉開(kāi)到 4ms 以上。

作用

也許有同學(xué)會(huì)問(wèn),有什么場(chǎng)景需要無(wú)延遲的定時(shí)器?其實(shí)在 React 的源碼中,做時(shí)間切片的部分就用到了。

const channel = new MessageChannel();
const port = channel.port2;

// 每次 port.postMessage() 調(diào)用就會(huì)添加一個(gè)宏任務(wù)
// 該宏任務(wù)為調(diào)用 scheduler.scheduleTask 方法
channel.port1.onmessage = scheduler.scheduleTask;

const scheduler = {
  scheduleTask() {
    // 挑選一個(gè)任務(wù)并執(zhí)行
    const task = pickTask();
    const continuousTask = task();

    // 如果當(dāng)前任務(wù)未完成,則在下個(gè)宏任務(wù)繼續(xù)執(zhí)行
    if (continuousTask) {
      port.postMessage(null);
    }
  },
};

React 把任務(wù)切分成很多片段,這樣就可以通過(guò)把任務(wù)交給postMessage的回調(diào)函數(shù),來(lái)讓瀏覽器主線程拿回控制權(quán),進(jìn)行一些更優(yōu)先的渲染任務(wù)(比如用戶輸入)。

為什么不用執(zhí)行時(shí)機(jī)更靠前的微任務(wù)呢?關(guān)鍵的原因在于微任務(wù)會(huì)在渲染之前執(zhí)行,這樣就算瀏覽器有緊急的渲染任務(wù),也得等微任務(wù)執(zhí)行完才能渲染。

總結(jié)

可以了解如下幾個(gè)知識(shí)點(diǎn):

  1. setTimeout的 4ms 延遲歷史原因,具體表現(xiàn)。
  2. 如何通過(guò)postMessage實(shí)現(xiàn)一個(gè)真正 0 延遲的定時(shí)器。
  3. postMessage定時(shí)器在 React 時(shí)間切片中的運(yùn)用。
  4. 為什么時(shí)間切片需要用宏任務(wù),而不是微任務(wù)。

本文轉(zhuǎn)載于:

https://juejin.cn/post/7229520942668824633

如果對(duì)您有所幫助,歡迎您點(diǎn)個(gè)關(guān)注,我會(huì)定時(shí)更新技術(shù)文檔,大家一起討論學(xué)習(xí),一起進(jìn)步。

?記錄--你敢信?比 setTimeout 還快 80 倍的定時(shí)器文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-821445.html

到了這里,關(guān)于記錄--你敢信?比 setTimeout 還快 80 倍的定時(shí)器的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • JavaScript定時(shí)器(setTimeout和setInterval)的用法技巧

    JavaScript定時(shí)器(setTimeout和setInterval)的用法技巧

    1.滿足特定條件時(shí)才執(zhí)行后續(xù)步驟。 核心代碼: 案例圖片: 場(chǎng)景解析:諸如 Promise 的情形,只有接口請(qǐng)求成功后才會(huì)執(zhí)行下一步。有時(shí)候不方便使用Promise或者特定情形下,可以借助此定時(shí)器( setInterval )方法解決。 友情提醒:業(yè)務(wù)處理完成后,一定要 清空 ( clearInterval

    2024年02月15日
    瀏覽(29)
  • 定時(shí)器的設(shè)置和清除setTimeout、setInterval、setImmediate-NodeJs

    JS是單線程運(yùn)行邏輯,所有的程序默認(rèn)在一個(gè)線程執(zhí)行,出現(xiàn)排隊(duì)執(zhí)行。所有的定時(shí)器中,回調(diào)函數(shù)會(huì)在主線程后事件隊(duì)列中執(zhí)行。 ? ? ? ? ? ? ?一次性定時(shí)器的 開(kāi)啟:當(dāng)間隔時(shí)間到了,會(huì)調(diào)用 一次 回調(diào)函數(shù),間隔時(shí)間的單位是毫秒。 ? ? ? ? ? ? ? var timer=setTimeout(回

    2024年02月04日
    瀏覽(18)
  • JavaScript【瀏覽器環(huán)境概述(BOM)、回流和重繪 、定時(shí)器之 setTimeout()、定時(shí)器之 setInterval()、定時(shí)器實(shí)操、防抖(debounce)】(十六)
  • Vue3 setup語(yǔ)法糖銷毀一個(gè)或多個(gè)定時(shí)器(setTimeout或setInterval)

    如果在頁(yè)面/組件增加了定時(shí)器,就算跳轉(zhuǎn)到其他頁(yè)面,定時(shí)器也不會(huì)被清理,這時(shí)候就需要手動(dòng)清理,不然會(huì)有意想不到的bug,也會(huì)影響性能。 setTimeout是只執(zhí)行一次,setInterval是循環(huán)執(zhí)行,以下是用setTimeout舉例子,如果想要用setInterval,替換一次方法就行。 setTimeout替換成

    2024年02月13日
    瀏覽(47)
  • 【學(xué)習(xí)記錄】STM32利用定時(shí)器中斷實(shí)現(xiàn)定時(shí)閃爍指示燈

    【學(xué)習(xí)記錄】STM32利用定時(shí)器中斷實(shí)現(xiàn)定時(shí)閃爍指示燈

    任務(wù):定時(shí)閃爍指示燈 任務(wù)目標(biāo): 掌握 CubeMX 軟件配置定時(shí)器實(shí)現(xiàn)定時(shí)功能的方法。 任務(wù)內(nèi)容: 控制開(kāi)發(fā)板上的指示燈LED每隔1s閃爍。 任務(wù)實(shí)現(xiàn): 使用的STM32芯片是STM32F407ZET6 第一步:設(shè)置高速時(shí)鐘,設(shè)置LED 第二步:配置TIM10時(shí)鐘為100MHz,故可以設(shè)置預(yù)分頻系數(shù)PSC為9999,自

    2024年02月05日
    瀏覽(26)
  • 關(guān)于單片機(jī)的分頻定時(shí)器的記錄

    關(guān)于單片機(jī)的分頻定時(shí)器的記錄

    對(duì)于單片機(jī)的頻率原來(lái)一直不太明白,現(xiàn)在在學(xué)習(xí)進(jìn)行記錄: 主頻: 分頻 對(duì)于分頻來(lái)說(shuō),實(shí)際就是相當(dāng)于間接降低這個(gè)主頻,減少這個(gè)震蕩次數(shù),比如我分頻系數(shù)為72,那么我就是1S產(chǎn)生的震蕩次數(shù)就是72000000/72=1000000次,相當(dāng)于用少的計(jì)數(shù)來(lái)對(duì)一秒鐘進(jìn)行計(jì)數(shù)。 那么有人好

    2024年04月09日
    瀏覽(24)
  • 定時(shí)器定時(shí)中斷&定時(shí)器外部時(shí)鐘

    定時(shí)器定時(shí)中斷&定時(shí)器外部時(shí)鐘

    1、RCC開(kāi)啟時(shí)鐘,此時(shí)定時(shí)器的基準(zhǔn)時(shí)鐘和整個(gè)外設(shè)的工作時(shí)鐘都打開(kāi) 2、選擇時(shí)基單元的時(shí)鐘源,對(duì)于定時(shí)中斷選擇內(nèi)部時(shí)鐘源 3、配置時(shí)基單元,包括預(yù)分頻器,自動(dòng)重裝器,計(jì)數(shù)模式等 4、配置輸出中斷控制允許更新中斷輸出到NVIC 5、配置NVIC,在NVIC中打開(kāi)定時(shí)器中斷的通

    2024年02月15日
    瀏覽(18)
  • STM-32:TIM定時(shí)中斷—定時(shí)器定時(shí)中斷/定時(shí)器外部時(shí)鐘

    STM-32:TIM定時(shí)中斷—定時(shí)器定時(shí)中斷/定時(shí)器外部時(shí)鐘

    定時(shí)器可以對(duì)輸入的時(shí)鐘進(jìn)行計(jì)數(shù),并在達(dá)到設(shè)定值時(shí)觸發(fā)中斷 16位計(jì)數(shù)器、預(yù)分頻器、自動(dòng)重裝寄存器的時(shí)基單元,在72MHz計(jì)數(shù)時(shí)鐘下可以實(shí)現(xiàn)最大59.65s的定時(shí) 不僅具備基本的定時(shí)中斷功能,而且還包含內(nèi)外時(shí)鐘源選擇、輸入捕獲、輸出比較、編碼器接口、主從觸發(fā)模式等

    2024年02月09日
    瀏覽(28)
  • STM32單片機(jī)(六)TIM定時(shí)器 -> 第二節(jié):TIM定時(shí)中斷練習(xí)(定時(shí)器定時(shí)中斷和定時(shí)器外部時(shí)鐘)

    STM32單片機(jī)(六)TIM定時(shí)器 -> 第二節(jié):TIM定時(shí)中斷練習(xí)(定時(shí)器定時(shí)中斷和定時(shí)器外部時(shí)鐘)

    ?? 專欄簡(jiǎn)介:本專欄記錄了從零學(xué)習(xí)單片機(jī)的過(guò)程,其中包括51單片機(jī)和STM32單片機(jī)兩部分;建議先學(xué)習(xí)51單片機(jī),其是STM32等高級(jí)單片機(jī)的基礎(chǔ);這樣再學(xué)習(xí)STM32時(shí)才能融會(huì)貫通。 ?? 專欄適用人群 :適用于想要從零基礎(chǔ)開(kāi)始學(xué)習(xí)入門單片機(jī),且有一定C語(yǔ)言基礎(chǔ)的的童鞋

    2024年02月09日
    瀏覽(31)
  • 【Qt】定時(shí)器處理——定時(shí)器事件類QTimerEvent和定時(shí)器類QTimer使用

    Qt的定時(shí)器只能通過(guò)純代碼實(shí)現(xiàn),定時(shí)器顧名思義,主要作用是定時(shí)特定的時(shí)間。 Qt提供了定時(shí)器事件類 QQTimerEvent 和定時(shí)器類 QTimer 實(shí)現(xiàn)定時(shí)器操作。 Qt提供了更高層次的定時(shí)器編程接口** QTimer **類,可以使用信號(hào)和槽,還可以設(shè)置定時(shí)一次。比較常用的方法有: QTimer::set

    2024年02月05日
    瀏覽(24)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包