JavaScript?定時(shí)器關(guān)鍵點(diǎn)及使用場(chǎng)景解析
正文
JavaScript 定時(shí)器是實(shí)現(xiàn)循環(huán)行為甚至觸發(fā)延遲操作的好功能。無論有什么基于時(shí)間的邏輯,定時(shí)器都可以提供支持。在 JavaScript 中有兩個(gè)定時(shí)器函數(shù):setTimeout 和 setInterval 。接下來看看有哪些定時(shí)器以及它們是如何工作的。
關(guān)于計(jì)時(shí)器的關(guān)鍵點(diǎn)
在深入了解定時(shí)器的具體細(xì)節(jié)之前,有幾個(gè)非常關(guān)鍵的點(diǎn)需要記住。
并不完全準(zhǔn)確
定時(shí)器要么在一定秒數(shù)后觸發(fā)一個(gè)動(dòng)作,要么在每次指定的超時(shí)結(jié)束時(shí)重復(fù)一個(gè)動(dòng)作。但是,盡管期望可能是它們精確到秒,但事實(shí)并非如此。
這些計(jì)時(shí)器的規(guī)范聲明它們將使用時(shí)間參數(shù)(如指定的秒數(shù))作為最短等待時(shí)間。但如果還有其他任務(wù)需要先完成,它們肯定會(huì)花費(fèi)更長的時(shí)間。
只有當(dāng)你邏輯依賴于精確的時(shí)間測(cè)量時(shí),這才會(huì)成為問題,比如讓時(shí)鐘通過 setInterval 回調(diào)來計(jì)算秒數(shù)。
異步函數(shù)
這意味著它們?cè)谕瓿芍安粫?huì)停止程序流。即使指定 0 作為超時(shí)值,它們的行為仍然是異步的。
這意味著這些函數(shù)會(huì)將對(duì)想要觸發(fā)的函數(shù)的引用添加到事件循環(huán)中,所以即使在超時(shí)值上指定了 0,引用也會(huì)在接下來發(fā)生的所有事情之后排隊(duì)。
setTimeout
setTimeout 函數(shù)可能是最容易理解的函數(shù),因?yàn)橹饕繕?biāo)是在幾秒后觸發(fā)一個(gè)函數(shù),只會(huì)執(zhí)行一次。
這個(gè)函數(shù)參數(shù)如下:
- 要執(zhí)行的函數(shù)引用:這是時(shí)間一到就會(huì)觸發(fā)的代碼邏輯。
- 函數(shù)執(zhí)行前的等待的秒數(shù)
- 然后所有其他參數(shù)以相同的順序傳遞給執(zhí)行的函數(shù)。
下面的代碼將在 3 秒后打印 Hello World:
setTimeout(console.log, 3000, "Hello", "World");
等效于以下代碼:
setTimeout(
(strHello, strWorld) => {
console.log(strHello, strWorld);
},
3000,
"Hello",
"World"
);
setTimeout 是一種特殊類型的異步函數(shù),因此無論在其后編寫什么代碼,都將在觸發(fā)該函數(shù)之前執(zhí)行,如下:
console.log("執(zhí)行了第 1 行代碼");
setTimeout(() => {
console.log("執(zhí)行了第 3 行代碼");
}, 1000);
console.log("執(zhí)行了第 5 行代碼");
console.log("執(zhí)行了第 6 行代碼");
setTimeout(function () {
console.log("執(zhí)行了第 8 行代碼");
}, 0);
console.log("執(zhí)行了第 10 行代碼");
輸出的結(jié)果如下:
執(zhí)行了第 1 行代碼
執(zhí)行了第 5 行代碼
執(zhí)行了第 6 行代碼
執(zhí)行了第 10 行代碼
執(zhí)行了第 8 行代碼
執(zhí)行了第 3 行代碼
請(qǐng)注意第 3 行和第 8 行是如何最后執(zhí)行的,即使第 8 行的超時(shí)為 0。
在討論 setTimeout 之前,如果設(shè)置超時(shí)值然后意識(shí)到必須停止它會(huì)發(fā)生什么?可以定義一個(gè)變量保存 setTimeout 的返回值(計(jì)時(shí)器 ID),則可以使用 clearTimeout 函數(shù)在超時(shí)之前停止計(jì)時(shí)器。
console.log("執(zhí)行了第 1 行代碼");
const timerId = setTimeout(() => {
console.log("執(zhí)行了第 3 行代碼");
}, 1000);
console.log("執(zhí)行了第 5 行代碼");
clearTimeout(timerId);
console.log("執(zhí)行了第 6 行代碼");
setTimeout(function () {
console.log("執(zhí)行了第 8 行代碼");
}, 0);
console.log("執(zhí)行了第 10 行代碼");
執(zhí)行結(jié)果如下,少了一個(gè)定時(shí)器的輸出:
執(zhí)行了第 1 行代碼
執(zhí)行了第 5 行代碼
執(zhí)行了第 6 行代碼
執(zhí)行了第 10 行代碼
執(zhí)行了第 8 行代碼
setInterval
setInterval 函數(shù)與 setTimeout 非常相似,但它不是只觸發(fā)一次函數(shù),而是一直觸發(fā)函數(shù)直到停止。
此函數(shù)的簽名與 setInterval 函數(shù)的簽名完全相同,所有參數(shù)的也相同。
const names = ["劉備", "關(guān)羽", "張飛", "趙云", "黃忠"];
function sayHi(list) {
let name = list[Math.round(Math.random() * 10) % 4];
console.log("你好!", name);
}
console.log("蜀漢五虎將");
const intervalID = setInterval(sayHi, 1000, names);
setTimeout(() => {
clearTimeout(intervalID);
}, 4000);
上面的代碼將啟動(dòng)一個(gè)每 1 秒觸發(fā)一次的循環(huán),當(dāng)它觸發(fā)時(shí),將選擇一個(gè)隨機(jī)名稱并打印字符串 你好! <name>。設(shè)置了 4 秒的超時(shí)時(shí)間,通過調(diào)用 clearTimeout 函數(shù)來結(jié)束無限循環(huán)。當(dāng)然,也可以使用 clearInterval 函數(shù),但由于它們使用相同的計(jì)時(shí)器池,可以互換使用它們。
區(qū)別
setTimeout 僅觸發(fā)一次表達(dá)式,而 setInterval 在給定的時(shí)間間隔后保持定期觸發(fā)表達(dá)式(除非手動(dòng)終止)。
使用場(chǎng)合
除了執(zhí)行定時(shí)操作,結(jié)合 Promise 方法,結(jié)合 setTimeout 可以實(shí)現(xiàn)休眠功能。
const sleep = (ms) => {
return new Promise((resolve) => setTimeout(resolve, ms));
};
const asyncFoo = async () => {
await sleep(2000);
console.log(" 等待2秒輸出");
await sleep(1000);
console.log(" 等待1秒輸出");
};
console.log("開始執(zhí)行");
asyncFoo();
Promise 結(jié)合 setInterval 可以實(shí)現(xiàn)一些數(shù)據(jù)的最大檢測(cè)次數(shù),如某個(gè)數(shù)據(jù)通過API驗(yàn)證,驗(yàn)證結(jié)果無法給出正常結(jié)果,超過一定次數(shù)提示錯(cuò)誤。
const fakeApiCheck = async () => {
console.log("檢查中...");
return Math.random() > 0.8;
};
const asyncInterval = async (callback, ms, triesLeft = 5) => {
return new Promise((resolve, reject) => {
const interval = setInterval(async () => {
if (await callback()) {
resolve();
clearInterval(interval);
} else if (triesLeft <= 1) {
reject();
clearInterval(interval);
}
triesLeft--;
}, ms);
});
};
const dataCheck = async () => {
try {
await asyncInterval(fakeApiCheck, 500);
} catch (e) {
console.log("驗(yàn)證錯(cuò)誤");
}
console.log("驗(yàn)證完成!");
};
dataCheck();
總結(jié)
計(jì)時(shí)器是生成重復(fù)或延遲行為的絕佳函數(shù),它們非常有用,尤其是當(dāng)必須在某些基于時(shí)間的條件下與其他服務(wù)進(jìn)行交互時(shí)。超時(shí)和間隔都可以在使用 clearInterval 或者 clearTimeout 函數(shù)觸發(fā)之前強(qiáng)制停止。
以上就是JavaScript 定時(shí)器關(guān)鍵點(diǎn)及使用場(chǎng)景解析的詳細(xì)內(nèi)容,更多關(guān)于JavaScript 定時(shí)器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解JavaScript實(shí)現(xiàn)簡(jiǎn)單的詞法分析器示例
這篇文章主要為大家介紹了詳解JavaScript實(shí)現(xiàn)簡(jiǎn)單的詞法分析器示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
JavaScript生成器函數(shù)Generator?Functions優(yōu)缺點(diǎn)特性詳解
這篇文章主要為大家介紹了JavaScript生成器函數(shù)Generator?Functions的特性及優(yōu)點(diǎn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05
JS前端使用canvas實(shí)現(xiàn)擴(kuò)展物體類和事件派發(fā)
這篇文章主要為大家介紹了JS前端使用canvas實(shí)現(xiàn)擴(kuò)展物體類和事件派發(fā)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08

