国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

js實(shí)現0ms延時(shí)定時(shí)器的幾種方式

發(fā)布時(shí)間:2021-08-17 12:16 來(lái)源: 閱讀:0 作者:福祿網(wǎng)絡(luò )技術(shù)團隊 欄目: JavaScript 歡迎投稿:712375056

目錄

這兩天看到一篇介紹《如何實(shí)現準時(shí)的 setTimeout?》的文章,文章起源于一道面試題:有什么辦法讓setTimeout準時(shí)呀?具體文章內容可查看附錄【1】,看完之后,引起了我對setTimeout這個(gè)函數的探究興趣,因此在MDN上重新查閱了相關(guān)文檔,其中提到【最小延時(shí) >=4ms】的一點(diǎn),因此使用setTimeout不能實(shí)現0ms延時(shí)的定時(shí)器,如果要實(shí)現的話(huà),提供了一個(gè)參考鏈接【2】,作者的實(shí)現思路是通過(guò)postMessage來(lái)模擬,繞過(guò)setTimeout的限制,從而實(shí)現0ms延時(shí)的定時(shí)器,說(shuō)簡(jiǎn)單來(lái)講就是起了一個(gè)宏任務(wù)去執行回調,先具體看下是怎么實(shí)現的:

(function() {
 var timeouts = [];
 var messageName = "zero-timeout-message";
 // Like setTimeout, but only takes a function argument.  There's
 // no time argument (always zero) and no arguments (you have to use a closure)
 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);

 // Add the one thing we want added to the window object.
 window.setZeroTimeout = setZeroTimeout;
})();

作者還提供了一個(gè)demo頁(yè)面【3】,通過(guò)于setTimeout(0)進(jìn)行對比,在我瀏覽器的執行結果如下:

100 iterations of setZeroTimeout took 15 milliseconds.
100 iterations of setTimeout(0) took 488 milliseconds.

根據結果對比來(lái)看,setZeroTimeout執行比setTimeout快了上百倍,這是一個(gè)巨大的提升。今天想討論的是除了上述這種方式,還可以通過(guò)哪些方式來(lái)實(shí)現一個(gè)0ms延時(shí)的定時(shí)器呢,首先,我們要確定一下我們自定義的定時(shí)器是異步的,其次是盡可能早的被執行。說(shuō)起異步,js提供了好幾種解決方案,我們可以逐一去驗證。

在深入討論各種實(shí)現方式之前,約定提供的setTimeout對比版本如下,后面自定義實(shí)現的方案都將和setTimeout版本的執行時(shí)間進(jìn)行對比,代碼比較簡(jiǎn)單:

(function() {
 let i = 0;
 const start = Date.now();
 function test() {
  if(i++ < 100) {
   setTimeout(test);
  } else {
   console.log('setTimeout執行時(shí)間:', Date.now() - start);
  }
 }
 setTimeout(test);
})();

queueMicrotask

queueMicrotask這個(gè)api可以添加一個(gè)微任務(wù),使用比較簡(jiǎn)單,直接傳遞一個(gè)回調函數即可,具體實(shí)現如下:

(function() {
 function setZeroTimeout(fn) {
  queueMicrotask(fn);
 }
 let i = 0;
 const start = Date.now();
 function test() {
  if(i++ < 100) {
   setZeroTimeout(test);
  } else {
   console.log('setZeroTimeout執行時(shí)間:', Date.now() - start);
  }
 }
 setZeroTimeout(test);
})();

通過(guò)和setTimeout版本進(jìn)行對比,最終結果如下:

setZeroTimeout執行時(shí)間: 2
setTimeout執行時(shí)間: 490

關(guān)于這個(gè)API的介紹在MDN上有詳細的說(shuō)明,就不展開(kāi)介紹了,這里多說(shuō)一點(diǎn),根據規范文檔的說(shuō)明,大多數情況下,推薦使用requestAnimationFrame()和requestIdleCallback()等api,因為queueMicrotask會(huì )阻塞渲染,在很多時(shí)候都不是一種好的實(shí)踐。

async/await

async/await對于前端開(kāi)發(fā)人員來(lái)說(shuō)已經(jīng)是必不可少的了,這里我們也可以用來(lái)實(shí)現:

(function() {
 async function setAsyncTimeout(fn) {
  Promise.resolve().then(fn);
 }
 let i = 0;
 const start = Date.now();
 async function test() {
  if (i++ < 100) {
   await setAsyncTimeout(test);
  } else {
   console.log('setAsyncTimeout執行時(shí)間:', Date.now() - start);
  }
 }
 setAsyncTimeout(test);
})();

通過(guò)和setTimeout版本進(jìn)行對比,最終結果如下:

setAsyncTimeout執行時(shí)間: 2
setTimeout執行時(shí)間: 490

如果不嫌麻煩,還可以通過(guò)Promise來(lái)實(shí)現,其實(shí)都是大同小異,無(wú)非多些點(diǎn)代碼,這里就省略了。

MessageChannel

MessageChannel允許我們創(chuàng )建一個(gè)新的消息通道,并通過(guò)它的兩個(gè)MessagePort屬性發(fā)送數據,MessageChannel提供端口的概念,實(shí)現端口之間的通信,比如worker/iframe之間的通信。

(function() {
 const channel = new MessageChannel();
 function setMessageChannelTimeout(fn) {
  channel.port2.postMessage(null);
 }
 channel.port1.onmessage = function() {
    test();
 };
 let i = 0;
 const start = Date.now();
 function test() {
  if(i++ < 100) {
   setMessageChannelTimeout(test);
  } else {
   console.log('setMessageChannelTimeout執行時(shí)間:', Date.now() - start);
  }
 }
 setMessageChannelTimeout(test);
})();

通過(guò)和setTimeout版本進(jìn)行對比,最終結果如下:

setMessageChannelTimeout執行時(shí)間: 4
setTimeout執行時(shí)間: 490

第三種方式運行時(shí)間比前面兩種更長(cháng)些,因為通過(guò)MessageChannel產(chǎn)生的是宏任務(wù),其他兩種是微任務(wù),微任務(wù)執行靠前,且會(huì )阻塞主線(xiàn)程,因此時(shí)間會(huì )長(cháng)一點(diǎn)。

最后

本文提供了三種實(shí)現方式,都是圍繞js提供異步解決方案來(lái)實(shí)現的,實(shí)現本身并不復雜。

附錄

​​【1】
【2】
【3】

到此這篇關(guān)于js實(shí)現0ms延時(shí)定時(shí)器的幾種方式的文章就介紹到這了,更多相關(guān)js 延時(shí)定時(shí)器 內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。

中文字幕久久精品一区二区三区| 国精产品自偷自偷综合下载| 国模安雅宾馆私拍鲜嫩玉门| 亚洲精品国产V片在线观看| 日韩三级| 国产95在线 | 亚洲|