最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

js中的兩種定時(shí)器區(qū)別是什么以及怎么清除定時(shí)器詳解

 更新時(shí)間:2026年01月12日 10:03:21   作者:董世昌41  
在做項(xiàng)目中難免會碰到需要實(shí)時(shí)刷新,動畫依次出現(xiàn)等等需求,這時(shí)候就需要定時(shí)器登上我們的代碼舞臺了,這篇文章主要介紹了js中兩種定時(shí)器區(qū)別是什么以及怎么清除定時(shí)器的相關(guān)資料,需要的朋友可以參考下

一、開篇:定時(shí)器 ——JavaScript 實(shí)現(xiàn)異步延遲的核心工具

在 JavaScript 中,作為一門單線程語言,實(shí)現(xiàn)異步操作和延遲執(zhí)行邏輯的核心工具之一就是定時(shí)器(Timer)。無論是實(shí)現(xiàn)頁面倒計(jì)時(shí)、輪播圖自動切換、接口定時(shí)輪詢,還是避免同步代碼阻塞頁面渲染,都離不開定時(shí)器的加持。

JavaScript 提供了兩種核心定時(shí)器方法:setTimeout() 和 setInterval(),很多初學(xué)者在使用時(shí)容易混淆二者的執(zhí)行邏輯,出現(xiàn) “定時(shí)器無法停止”“執(zhí)行時(shí)機(jī)不符合預(yù)期” 等問題 —— 比如用setInterval()實(shí)現(xiàn)倒計(jì)時(shí)出現(xiàn)時(shí)間跳變、清除定時(shí)器后仍有殘留執(zhí)行邏輯。

本文將從兩種定時(shí)器的核心定義、執(zhí)行機(jī)制、核心區(qū)別,到定時(shí)器的清除方法、實(shí)戰(zhàn)避坑指南,結(jié)合完整示例深度拆解,幫你徹底掌握 JS 定時(shí)器的使用精髓,寫出健壯、可控的異步延遲代碼。

二、第一部分:認(rèn)識 JS 的兩種核心定時(shí)器

1. 一次性定時(shí)器:setTimeout ()

(1)核心定義

setTimeout() 是用于 ** 在指定的延遲時(shí)間后,一次性執(zhí)行某段代碼(回調(diào)函數(shù))** 的定時(shí)器,執(zhí)行完畢后定時(shí)器自動失效,不會重復(fù)觸發(fā),因此也被稱為 “一次性定時(shí)器” 或 “延遲定時(shí)器”。

(2)語法格式

// 基礎(chǔ)語法:返回定時(shí)器ID(用于后續(xù)清除定時(shí)器)
const timeoutId = setTimeout(callback, delay, [param1, param2, ...]);
  • 關(guān)鍵參數(shù)說明:

    callback:必填,延遲后要執(zhí)行的回調(diào)函數(shù)(可以是普通函數(shù)、箭頭函數(shù),也可以是字符串形式的代碼片段,不推薦后者,存在安全風(fēng)險(xiǎn)且性能較差);

    delay:可選,延遲執(zhí)行的時(shí)間,單位為毫秒(ms),默認(rèn)值為0(注意:不是立即執(zhí)行,后續(xù)會詳解);

    param1, param2, ...:可選,傳遞給回調(diào)函數(shù)的參數(shù),在 ES5 及以上環(huán)境中支持;

    返回值timeoutId:非負(fù)整數(shù)(定時(shí)器唯一標(biāo)識 ID),每個定時(shí)器對應(yīng)一個唯一 ID,用于后續(xù)清除該定時(shí)器。

(3)實(shí)戰(zhàn)示例

// 示例1:基礎(chǔ)使用——3秒后一次性執(zhí)行回調(diào)
const timeoutId1 = setTimeout(() => {
  console.log("3秒后執(zhí)行,僅執(zhí)行一次");
}, 3000);

console.log("定時(shí)器已創(chuàng)建,ID為:", timeoutId1); // 輸出:定時(shí)器已創(chuàng)建,ID為:1(不同環(huán)境ID可能不同)

// 示例2:傳遞參數(shù)給回調(diào)函數(shù)
const timeoutId2 = setTimeout((name, age) => {
  console.log(`你好,我是${name},今年${age}歲`);
}, 2000, "張三", 25); // 2秒后輸出:你好,我是張三,今年25歲

// 示例3:延遲時(shí)間為0(非立即執(zhí)行,進(jìn)入任務(wù)隊(duì)列等待執(zhí)行)
setTimeout(() => {
  console.log("延遲0毫秒,最后執(zhí)行");
}, 0);

console.log("同步代碼,先執(zhí)行");
// 輸出順序:同步代碼,先執(zhí)行 → 延遲0毫秒,最后執(zhí)行

(4)核心執(zhí)行機(jī)制

setTimeout() 的延遲時(shí)間delay并非 “絕對準(zhǔn)確”,也不是 “到點(diǎn)立即執(zhí)行”,核心原因是 JavaScript 的單線程特性:

  • 當(dāng)調(diào)用setTimeout()時(shí),JS 引擎會將回調(diào)函數(shù)放入宏任務(wù)隊(duì)列,并記錄延遲時(shí)間;
  • 主線程優(yōu)先執(zhí)行完當(dāng)前所有同步代碼,再去處理宏任務(wù)隊(duì)列;
  • 只有當(dāng)主線程空閑,且延遲時(shí)間已到,回調(diào)函數(shù)才會被執(zhí)行;
  • 若主線程被其他耗時(shí)同步代碼阻塞,回調(diào)函數(shù)的執(zhí)行時(shí)間會大于delay設(shè)定的時(shí)間。

2. 周期性定時(shí)器:setInterval ()

(1)核心定義

setInterval() 是用于 ** 按照指定的時(shí)間間隔,周期性、重復(fù)執(zhí)行某段代碼(回調(diào)函數(shù))** 的定時(shí)器,除非手動清除,否則會一直持續(xù)執(zhí)行,因此也被稱為 “周期性定時(shí)器” 或 “重復(fù)定時(shí)器”。

(2)語法格式

// 基礎(chǔ)語法:返回定時(shí)器ID(用于后續(xù)清除定時(shí)器)
const intervalId = setInterval(callback, delay, [param1, param2, ...]);
  • 關(guān)鍵參數(shù)說明(與setTimeout()一致,核心差異在執(zhí)行邏輯):

    callback:必填,每次間隔時(shí)間到后要執(zhí)行的回調(diào)函數(shù);

    delay:可選,兩次回調(diào)執(zhí)行之間的時(shí)間間隔,單位為毫秒(ms),默認(rèn)值為0;

    param1, param2, ...:可選,傳遞給回調(diào)函數(shù)的參數(shù);

    返回值intervalId:非負(fù)整數(shù)(定時(shí)器唯一標(biāo)識 ID),用于后續(xù)清除該周期性定時(shí)器。

(3)實(shí)戰(zhàn)示例

// 示例1:基礎(chǔ)使用——每隔2秒重復(fù)執(zhí)行回調(diào)
let count = 0;
const intervalId1 = setInterval(() => {
  count++;
  console.log(`已執(zhí)行${count}次,每隔2秒執(zhí)行一次`);
}, 2000);

// 示例2:傳遞參數(shù)給回調(diào)函數(shù),實(shí)現(xiàn)倒計(jì)時(shí)
let remainingTime = 10;
const intervalId2 = setInterval((title) => {
  remainingTime--;
  console.log(`${title}:剩余${remainingTime}秒`);
  if (remainingTime <= 0) {
    console.log("倒計(jì)時(shí)結(jié)束");
    // 后續(xù)會詳解:倒計(jì)時(shí)結(jié)束后清除定時(shí)器
    clearInterval(intervalId2);
  }
}, 1000, "秒殺活動"); // 每隔1秒輸出一次倒計(jì)時(shí)

(4)核心執(zhí)行機(jī)制

setInterval() 的執(zhí)行機(jī)制與setTimeout() 類似,同樣受 JS 單線程和宏任務(wù)隊(duì)列影響,但存在一個關(guān)鍵差異:

  • 首次調(diào)用setInterval()時(shí),JS 引擎會將回調(diào)函數(shù)放入宏任務(wù)隊(duì)列,等待延遲時(shí)間delay后執(zhí)行;
  • 回調(diào)函數(shù)執(zhí)行完畢后,setInterval() 會再次將下一次的回調(diào)函數(shù)放入宏任務(wù)隊(duì)列,保持delay時(shí)間間隔的周期性;
  • 若某一次回調(diào)函數(shù)執(zhí)行耗時(shí)超過delay時(shí)間間隔,后續(xù)回調(diào)會出現(xiàn) “堆積”,導(dǎo)致執(zhí)行間隔小于delay(這是setInterval() 的常見坑);
  • 除非手動清除,否則該過程會一直循環(huán),直到頁面卸載或定時(shí)器被清除。

三、第二部分:兩種定時(shí)器的核心區(qū)別(5 大維度對比)

setTimeout() 和 setInterval() 雖然都是定時(shí)器,且語法格式相似,但在執(zhí)行邏輯、使用場景等方面存在本質(zhì)區(qū)別,通過以下 5 大維度可直觀區(qū)分:

對比維度一次性定時(shí)器(setTimeout ())周期性定時(shí)器(setInterval ())
執(zhí)行次數(shù)僅執(zhí)行一次,回調(diào)執(zhí)行完畢后定時(shí)器自動失效重復(fù)執(zhí)行多次,直到手動清除或頁面卸載
核心用途實(shí)現(xiàn)單次延遲執(zhí)行(如延遲提示、防抖兜底)實(shí)現(xiàn)周期性重復(fù)執(zhí)行(如倒計(jì)時(shí)、輪詢、輪播)
定時(shí)器狀態(tài)執(zhí)行后自動失效,無需手動清除(除非提前終止)持續(xù)處于激活狀態(tài),必須手動清除否則一直執(zhí)行
時(shí)間特性延遲delay毫秒后執(zhí)行單次回調(diào)每隔delay毫秒執(zhí)行一次回調(diào),存在執(zhí)行堆積風(fēng)險(xiǎn)
底層邏輯單次將回調(diào)放入宏任務(wù)隊(duì)列周期性將回調(diào)放入宏任務(wù)隊(duì)列,形成循環(huán)

補(bǔ)充:關(guān)鍵差異實(shí)戰(zhàn)驗(yàn)證

// 1. setTimeout():僅執(zhí)行一次
setTimeout(() => {
  console.log("setTimeout:我只執(zhí)行一次");
}, 1000);

// 2. setInterval():重復(fù)執(zhí)行,需手動清除
let times = 0;
const intervalId = setInterval(() => {
  times++;
  console.log(`setInterval:我執(zhí)行了${times}次`);
  if (times === 3) {
    clearInterval(intervalId); // 執(zhí)行3次后手動清除
    console.log("setInterval:我被清除了,停止執(zhí)行");
  }
}, 1000);

輸出結(jié)果順序

plaintext

setTimeout:我只執(zhí)行一次
setInterval:我執(zhí)行了1次
setInterval:我執(zhí)行了2次
setInterval:我執(zhí)行了3次
setInterval:我被清除了,停止執(zhí)行

四、第三部分:如何清除定時(shí)器?(核心方法與實(shí)戰(zhàn))

無論是setTimeout() 還是 setInterval(),創(chuàng)建時(shí)都會返回一個唯一的定時(shí)器 ID,清除定時(shí)器的核心就是通過這個 ID,調(diào)用對應(yīng)的清除方法,終止定時(shí)器的執(zhí)行(或周期性執(zhí)行)。

1. 對應(yīng)清除方法:一對一清除,不可混用

JS 提供了兩個專門的定時(shí)器清除方法,分別對應(yīng)兩種定時(shí)器,需一一對應(yīng)使用,不可混用(雖然混用在部分瀏覽器中可能生效,但不符合規(guī)范,存在兼容性風(fēng)險(xiǎn))。

(1)清除一次性定時(shí)器:clearTimeout ()

核心功能:用于清除由setTimeout() 創(chuàng)建的一次性定時(shí)器,終止回調(diào)函數(shù)的執(zhí)行(僅對未執(zhí)行的定時(shí)器有效,若回調(diào)已執(zhí)行,定時(shí)器已失效,調(diào)用該方法無任何效果)。

語法格式

// timeoutId 是 setTimeout() 返回的定時(shí)器ID
clearTimeout(timeoutId);

實(shí)戰(zhàn)示例

// 1. 創(chuàng)建一次性定時(shí)器
const timeoutId = setTimeout(() => {
  console.log("該回調(diào)不會被執(zhí)行,因?yàn)槎〞r(shí)器被提前清除了");
}, 3000);

console.log("創(chuàng)建定時(shí)器,準(zhǔn)備2秒后清除它");

// 2. 提前2秒清除定時(shí)器(此時(shí)回調(diào)還未執(zhí)行)
setTimeout(() => {
  clearTimeout(timeoutId);
  console.log("定時(shí)器已被清除,回調(diào)終止執(zhí)行");
}, 2000);

(2)清除周期性定時(shí)器:clearInterval ()

核心功能:用于清除由setInterval() 創(chuàng)建的周期性定時(shí)器,終止回調(diào)函數(shù)的后續(xù)重復(fù)執(zhí)行(調(diào)用后,定時(shí)器立即失效,不再向宏任務(wù)隊(duì)列添加新的回調(diào))。

語法格式

// intervalId 是 setInterval() 返回的定時(shí)器ID
clearInterval(intervalId);

實(shí)戰(zhàn)示例

// 1. 創(chuàng)建周期性定時(shí)器(實(shí)現(xiàn)倒計(jì)時(shí))
let countdown = 5;
const intervalId = setInterval(() => {
  countdown--;
  if (countdown > 0) {
    console.log(`倒計(jì)時(shí)剩余:${countdown}秒`);
  } else {
    console.log("倒計(jì)時(shí)結(jié)束,清除定時(shí)器");
    // 2. 倒計(jì)時(shí)結(jié)束,清除周期性定時(shí)器
    clearInterval(intervalId);
  }
}, 1000);

輸出結(jié)果

plaintext

倒計(jì)時(shí)剩余:4秒
倒計(jì)時(shí)剩余:3秒
倒計(jì)時(shí)剩余:2秒
倒計(jì)時(shí)剩余:1秒
倒計(jì)時(shí)結(jié)束,清除定時(shí)器

2. 清除定時(shí)器的關(guān)鍵注意事項(xiàng)

(1)必須保存定時(shí)器 ID,否則無法精準(zhǔn)清除

創(chuàng)建定時(shí)器時(shí),一定要將返回的 ID 賦值給變量保存,若丟失 ID,將無法精準(zhǔn)清除該定時(shí)器,只能等待頁面卸載或使用clearTimeout()/clearInterval() 不帶參數(shù)清除所有定時(shí)器(不推薦,會清除其他無關(guān)定時(shí)器)。

// 錯誤示例:未保存定時(shí)器ID,無法精準(zhǔn)清除
setInterval(() => {
  console.log("無法精準(zhǔn)清除,只能一直執(zhí)行到頁面卸載");
}, 1000);

// 正確示例:保存定時(shí)器ID,便于后續(xù)精準(zhǔn)清除
const intervalId = setInterval(() => {
  console.log("可通過ID精準(zhǔn)清除");
}, 1000);
clearInterval(intervalId);

(2)避免 “定時(shí)器泄漏”:組件卸載 / 頁面關(guān)閉前清除定時(shí)器

在前端框架(React、Vue)開發(fā)中,若組件中創(chuàng)建了定時(shí)器,在組件卸載時(shí)未清除,會導(dǎo)致 “定時(shí)器泄漏”—— 組件已銷毀,但定時(shí)器仍在后臺執(zhí)行,不僅浪費(fèi)內(nèi)存,還可能引發(fā)報(bào)錯(如訪問已銷毀的組件 DOM)。

Vue 組件示例(組件卸載前清除定時(shí)器)

<template>
  <div>組件倒計(jì)時(shí):{{ countdown }}</div>
</template>

<script>
export default {
  data() {
    return {
      countdown: 10,
      intervalId: null // 保存定時(shí)器ID
    };
  },
  mounted() {
    // 創(chuàng)建周期性定時(shí)器
    this.intervalId = setInterval(() => {
      this.countdown--;
      if (this.countdown <= 0) {
        clearInterval(this.intervalId);
      }
    }, 1000);
  },
  beforeUnmount() {
    // 組件卸載前清除定時(shí)器,避免泄漏
    if (this.intervalId) {
      clearInterval(this.intervalId);
    }
  }
};
</script>

(3)延遲時(shí)間為 0 的定時(shí)器,仍可被清除

即使setTimeout() 的延遲時(shí)間設(shè)為0,回調(diào)函數(shù)仍未立即執(zhí)行(處于宏任務(wù)隊(duì)列等待),此時(shí)調(diào)用clearTimeout() 仍可終止其執(zhí)行。

const timeoutId = setTimeout(() => {
  console.log("該回調(diào)不會被執(zhí)行");
}, 0);

clearTimeout(timeoutId); // 立即清除,回調(diào)無法執(zhí)行

(4)清除已失效 / 不存在的定時(shí)器,不會報(bào)錯

若對已執(zhí)行完畢的setTimeout() 定時(shí)器、已清除的setInterval() 定時(shí)器,或不存在的 ID 調(diào)用清除方法,JS 引擎不會拋出錯誤,僅會靜默失敗,無需額外做判斷(若需嚴(yán)謹(jǐn),可先判斷 ID 是否存在)。

// 1. 清除已執(zhí)行完畢的setTimeout()定時(shí)器
const timeoutId = setTimeout(() => {
  console.log("回調(diào)已執(zhí)行");
}, 1000);

// 2秒后回調(diào)已執(zhí)行,定時(shí)器已失效
setTimeout(() => {
  clearTimeout(timeoutId); // 無報(bào)錯,靜默失敗
}, 2000);

// 3. 清除不存在的定時(shí)器ID
clearInterval(9999); // 無報(bào)錯,靜默失敗

五、第四部分:實(shí)戰(zhàn)避坑指南 —— 定時(shí)器的常見問題與解決方案

1. 坑 1:setInterval () 回調(diào)執(zhí)行堆積,導(dǎo)致間隔不準(zhǔn)

問題現(xiàn)象:當(dāng)setInterval() 的回調(diào)函數(shù)執(zhí)行耗時(shí)超過delay時(shí)間間隔,后續(xù)回調(diào)會在宏任務(wù)隊(duì)列中堆積,回調(diào)執(zhí)行間隔小于預(yù)期的delay。

解決方案:使用setTimeout() 嵌套調(diào)用,模擬周期性執(zhí)行,避免堆積(每次回調(diào)執(zhí)行完畢后,再創(chuàng)建下一個定時(shí)器,保證間隔準(zhǔn)確)。

// 推薦:setTimeout() 嵌套,實(shí)現(xiàn)精準(zhǔn)間隔的周期性執(zhí)行
let count = 0;
function periodicExecute() {
  // 1. 執(zhí)行核心業(yè)務(wù)邏輯
  count++;
  console.log(`執(zhí)行第${count}次,間隔2秒`);

  // 2. 回調(diào)執(zhí)行完畢后,創(chuàng)建下一個定時(shí)器,保證間隔準(zhǔn)確
  if (count < 5) {
    setTimeout(periodicExecute, 2000);
  }
}

// 啟動周期性執(zhí)行
setTimeout(periodicExecute, 2000);

2. 坑 2:混淆 “延遲時(shí)間” 與 “執(zhí)行時(shí)間”,預(yù)期不符

問題現(xiàn)象:認(rèn)為setTimeout(fn, 1000) 會在 1 秒后 “絕對準(zhǔn)確” 執(zhí)行,但實(shí)際執(zhí)行時(shí)間可能大于 1 秒(受主線程同步代碼阻塞影響)。

解決方案

  • 理解 JS 單線程和宏任務(wù)隊(duì)列機(jī)制,不依賴定時(shí)器的絕對準(zhǔn)確時(shí)間;
  • 若需高精度定時(shí),可使用requestAnimationFrame()(適合動畫場景,刷新率與屏幕同步)或Web Worker(避免主線程阻塞)。

3. 坑 3:清除定時(shí)器后,仍執(zhí)行一次回調(diào)

問題現(xiàn)象:清除周期性定時(shí)器后,回調(diào)函數(shù)仍執(zhí)行了一次,核心原因是:清除時(shí),下一個回調(diào)已經(jīng)被放入宏任務(wù)隊(duì)列,等待執(zhí)行。

解決方案

  • 清除定時(shí)器前,增加狀態(tài)判斷,避免回調(diào)執(zhí)行無效邏輯;
  • 使用setTimeout() 嵌套替代setInterval(),從根源上避免該問題。
let isActive = true; // 狀態(tài)標(biāo)記
let count = 0;

const intervalId = setInterval(() => {
  // 增加狀態(tài)判斷,即使回調(diào)已入隊(duì),也不執(zhí)行無效邏輯
  if (!isActive) return;
  
  count++;
  console.log(`執(zhí)行第${count}次`);
}, 1000);

// 2.5秒后清除定時(shí)器
setTimeout(() => {
  isActive = false; // 先標(biāo)記狀態(tài)為無效
  clearInterval(intervalId); // 再清除定時(shí)器
  console.log("定時(shí)器已清除");
}, 2500);

六、總結(jié):核心知識點(diǎn)回顧與實(shí)戰(zhàn)準(zhǔn)則

  • 兩種定時(shí)器的核心定位setTimeout() 是 “單次延遲”,setInterval() 是 “周期性重復(fù)”,根據(jù)業(yè)務(wù)場景選擇對應(yīng)工具;
  • 清除定時(shí)器的核心:保存定時(shí)器 ID,使用clearTimeout()/clearInterval() 一對一清除,組件卸載 / 頁面關(guān)閉前避免泄漏;
  • 實(shí)戰(zhàn)準(zhǔn)則
    • 優(yōu)先使用setTimeout() 嵌套實(shí)現(xiàn)精準(zhǔn)周期性執(zhí)行,避免setInterval() 堆積問題;
    • 避免依賴定時(shí)器的絕對準(zhǔn)確時(shí)間,理解 JS 單線程執(zhí)行機(jī)制;
    • 保存定時(shí)器 ID,精準(zhǔn)清除,杜絕 “定時(shí)器泄漏”。

定時(shí)器作為 JS 異步編程的基礎(chǔ)工具,看似簡單,實(shí)則蘊(yùn)含著單線程、任務(wù)隊(duì)列的核心思想。掌握兩種定時(shí)器的區(qū)別與清除方法,不僅能解決日常開發(fā)中的延遲、重復(fù)執(zhí)行需求,更能為后續(xù)深入學(xué)習(xí) Promise、async/await 等異步編程技術(shù)打下堅(jiān)實(shí)基礎(chǔ)。

最后用一句話總結(jié):setTimeout() 是 “一次性的等待”,setInterval() 是 “無休止的循環(huán)”,清除定時(shí)器是 “及時(shí)止損的智慧”,選對、用對、清對,才能駕馭 JS 的異步延遲邏輯。

到此這篇關(guān)于js中的兩種定時(shí)器區(qū)別是什么以及怎么清除定時(shí)器的文章就介紹到這了,更多相關(guān)js兩種定時(shí)器區(qū)別及清除內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

仙居县| 正安县| 阿勒泰市| 彰武县| 贞丰县| 都兰县| 都兰县| 松潘县| 宜宾市| 都兰县| 田林县| 林州市| 固始县| 乌兰浩特市| 英吉沙县| 阿拉善右旗| 柳州市| 喀喇沁旗| 通城县| 静乐县| 南京市| 重庆市| 林周县| 醴陵市| 天祝| 石狮市| 景谷| 逊克县| 萝北县| 青州市| 英吉沙县| 锡林浩特市| 阜宁县| 高安市| 会东县| 滕州市| 峨眉山市| 闸北区| 额济纳旗| 义乌市| 金坛市|