【每日一題】為什么使用 setTimeout 實(shí)現(xiàn) setInterval?

人生苦短,總需要一點(diǎn)儀式感。比如學(xué)前端~
分析
setInterval 的作用是每隔一段指定時(shí)間執(zhí)行一個(gè)函數(shù),但是這個(gè)執(zhí)行不是真的到了時(shí)間立即執(zhí)行,它真正的作用是每隔一段時(shí)間將事件加入事件隊(duì)列中,只有當(dāng)目前的執(zhí)行棧為空的時(shí)候,才能去事件隊(duì)列中取出事件執(zhí)行。
所以可能會(huì)出現(xiàn)這樣的情況:若當(dāng)前執(zhí)行棧執(zhí)行的時(shí)間很長(zhǎng),導(dǎo)致事件隊(duì)列里邊積累多個(gè)定時(shí)器加入的事件,當(dāng)執(zhí)行棧結(jié)束的時(shí)候,這些事件會(huì)依次執(zhí)行,因此可能就不能實(shí)現(xiàn)“到間隔一段時(shí)間執(zhí)行”的效果。
針對(duì) setInterval 的這個(gè)缺點(diǎn),我們可以使用 setTimeout 遞歸調(diào)用來(lái)模擬 setInterval,這樣我們就能確保實(shí)現(xiàn)“一個(gè)事件結(jié)束了、才觸發(fā)下一個(gè)定時(shí)器事件”的效果,以解決了 setInterval 的問(wèn)題。
模擬實(shí)現(xiàn)
接下來(lái)我們使用 setTimeout 模擬實(shí)現(xiàn) setInterval,思路是使用遞歸函數(shù),不斷地執(zhí)行 setTimeout 從而達(dá)到 setInterval 的效果。
簡(jiǎn)單實(shí)現(xiàn)
代碼實(shí)現(xiàn)
function mySetInterval(fn, interval) {
// 設(shè)置遞歸函數(shù),模擬定時(shí)器執(zhí)行。
function callback() {
fn();
setTimeout(callback, interval);
}
// 啟動(dòng)定時(shí)器
setTimeout(callback, interval);
}
執(zhí)行測(cè)試
var i = 0;
mySetInterval(() => {
i++;
console.log(i, '測(cè)試打印')
}, 1000);

進(jìn)階版:控制是否繼續(xù)執(zhí)行
function mySetInterval(fn, interval) {
// 控制器,控制定時(shí)器是否繼續(xù)執(zhí)行
var timer = {
flag: true,
};
// 設(shè)置遞歸函數(shù),模擬定時(shí)器執(zhí)行。
function callback() {
if (timer.flag) { // 判斷是否繼續(xù)執(zhí)行
fn();
setTimeout(callback, interval);
}
}
// 啟動(dòng)定時(shí)器
setTimeout(callback, interval);
// 返回控制器
return timer;
}
// 使用
let timer = mySetInterval(() => {
console.log(123)
}, 1000)
setTimeout(() => {
timer.flag = false
}, 4000)


讓我們一起攜手同走前端路!
關(guān)注公眾號(hào)回復(fù)【加群】即可

● 工作中常見(jiàn)頁(yè)面布局的n種實(shí)現(xiàn)方法
● 三欄響應(yīng)式布局(左右固寬中間自適應(yīng))的5種方法
● 兩欄自適應(yīng)布局的n種實(shí)現(xiàn)方法匯總
