您好,登錄后才能下訂單哦!
小編給大家分享一下js如何實(shí)現(xiàn)0ms延時定時器,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
示例如下
(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; })();
作者還提供了一個demo頁面【3】,通過于setTimeout(0)進(jìn)行對比,在我瀏覽器的執(zhí)行結(jié)果如下:
100 iterations of setZeroTimeout took 15 milliseconds.
100 iterations of setTimeout(0) took 488 milliseconds.
根據(jù)結(jié)果對比來看,setZeroTimeout執(zhí)行比setTimeout快了上百倍,這是一個巨大的提升。今天想討論的是除了上述這種方式,還可以通過哪些方式來實(shí)現(xiàn)一個0ms延時的定時器呢,首先,我們要確定一下我們自定義的定時器是異步的,其次是盡可能早的被執(zhí)行。說起異步,js提供了好幾種解決方案,我們可以逐一去驗(yàn)證。
在深入討論各種實(shí)現(xiàn)方式之前,約定提供的setTimeout對比版本如下,后面自定義實(shí)現(xiàn)的方案都將和setTimeout版本的執(zhí)行時間進(jìn)行對比,代碼比較簡單:
(function() { let i = 0; const start = Date.now(); function test() { if(i++ < 100) { setTimeout(test); } else { console.log('setTimeout執(zhí)行時間:', Date.now() - start); } } setTimeout(test); })();
queueMicrotask這個api可以添加一個微任務(wù),使用比較簡單,直接傳遞一個回調(diào)函數(shù)即可,具體實(shí)現(xiàn)如下:
(function() { function setZeroTimeout(fn) { queueMicrotask(fn); } let i = 0; const start = Date.now(); function test() { if(i++ < 100) { setZeroTimeout(test); } else { console.log('setZeroTimeout執(zhí)行時間:', Date.now() - start); } } setZeroTimeout(test); })();
通過和setTimeout版本進(jìn)行對比,最終結(jié)果如下:
setZeroTimeout執(zhí)行時間: 2
setTimeout執(zhí)行時間: 490
關(guān)于這個API的介紹在MDN上有詳細(xì)的說明,就不展開介紹了,這里多說一點(diǎn),根據(jù)規(guī)范文檔的說明,大多數(shù)情況下,推薦使用requestAnimationFrame()和requestIdleCallback()等api,因?yàn)閝ueueMicrotask會阻塞渲染,在很多時候都不是一種好的實(shí)踐。
async/await對于前端開發(fā)人員來說已經(jīng)是必不可少的了,這里我們也可以用來實(shí)現(xiàn):
(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執(zhí)行時間:', Date.now() - start); } } setAsyncTimeout(test); })();
通過和setTimeout版本進(jìn)行對比,最終結(jié)果如下:
setAsyncTimeout執(zhí)行時間: 2
setTimeout執(zhí)行時間: 490
如果不嫌麻煩,還可以通過Promise來實(shí)現(xiàn),其實(shí)都是大同小異,無非多些點(diǎn)代碼,這里就省略了。
MessageChannel允許我們創(chuàng)建一個新的消息通道,并通過它的兩個MessagePort屬性發(fā)送數(shù)據(jù),MessageChannel提供端口的概念,實(shí)現(xiàn)端口之間的通信,比如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執(zhí)行時間:', Date.now() - start); } } setMessageChannelTimeout(test); })();
通過和setTimeout版本進(jìn)行對比,最終結(jié)果如下:
setMessageChannelTimeout執(zhí)行時間: 4
setTimeout執(zhí)行時間: 490
第三種方式運(yùn)行時間比前面兩種更長些,因?yàn)橥ㄟ^MessageChannel產(chǎn)生的是宏任務(wù),其他兩種是微任務(wù),微任務(wù)執(zhí)行靠前,且會阻塞主線程,因此時間會長一點(diǎn)。
以上是“js如何實(shí)現(xiàn)0ms延時定時器”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。