关于setInterval()你所不知道的地方

本文详细探讨了JavaScript中setInterval与setTimeout的区别与使用技巧,包括它们的运行机制、实际应用案例及如何避免常见陷阱。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址,点击查看

关于setInterval()你所不知道的地方

    <div class="postBody">
        <div id="cnblogs_post_body" class="blogpost-body"><p><span style="font-family: 黑体;">前言:1.使用setInterval()的定时器会把事件运行的时间也包含在内,如果要精确算定时两个任务之间的时间,可以使用setTimeout()替换。2.当异步事件发生时,如mouse click, a timer firing, or an XMLHttpRequest completing(鼠标点击事件发生、定时器触发事件发生、XMLHttpRequest完成回调触发等),将他们放入执行队列,等待当前<span class="wp_keywordlink"><a title="代码" href="http://caibaojian.com/c/code">代码</a>执行完成。</span></span></p>

1. setInterval()基础

setInterval函数的用法与setTimeout完全一致,区别仅仅在于setInterval指定某个任务每隔一段时间就执行一次,也就是无限次的定时执行。

<input type="button" οnclick="clearInterval(timer)" value="stop">

<script>  var i = 1  var timer = setInterval(function() {  console.log(2);  }, 1000); </script>

上面代码表示每隔1000毫秒就输出一个2,直到用户点击了停止按钮。

与setTimeout一样,除了前两个参数,setInterval 方法还可以接受更多的参数,它们会传入回调函数,下面是一个例子。

function f(){
 for (var i=0;i<arguments.length;i++){  console.log(arguments[i]);  } } setInterval(f, 1000, "Hello World"); // Hello World // Hello World // Hello World // ...

如果网页不在浏览器的当前窗口(或tab),许多浏览器限制setInteral指定的反复运行的任务最多每秒执行一次。

setInterval指定的是“开始执行”之间的间隔,并不考虑每次任务执行本身所消耗的事件。因此实际上,两次执行之间的间隔会小于指定的时间。比如,setInterval指定每100ms执行一次,每次执行需要5ms,那么第一次执行结束后95毫秒,第二次执行就会开始。如果某次执行耗时特别长,比如需要105毫秒,那么它结束后,下一次执行就会立即开始。

var i = 1;
var timer = setInterval(function() {  alert(i++); }, 2000);

上面代码每隔2000毫秒,就跳出一个alert对话框。如果用户一直不点击“确定”,整个浏览器就处于“堵塞”状态,后面的执行就一直无法触发,将会累积起来。举例来说,第一次跳出alert对话框后,用户过了6000毫秒才点击“确定”,那么第二次、第三次、第四次执行将累积起来,它们之间不会再有等待间隔。

为了确保两次执行之间有固定的间隔,可以不用setInterval,而是每次执行结束后,使用setTimeout指定下一次执行的具体时间。上面代码用setTimeout,可以改写如下。

var i = 1;
var timer = setTimeout(function() {  alert(i++);  timer = setTimeout(arguments.callee, 2000); }, 2000);

上面代码可以确保两次执行的间隔是2000毫秒。

根据这种思路,可以自己部署一个函数,实现间隔时间确定的setInterval的效果。

function interval(func, wait){
 var interv = function(){  func.call(null);  setTimeout(interv, wait);  };  setTimeout(interv, wait); } interval(function(){  console.log(2); },1000);

上面代码部署了一个interval函数,用循环调用setTimeout模拟了setInterval。

html 5标准规定,setInterval的最短间隔时间是10毫秒,也就是说,小于10毫秒的时间间隔会被调整到10毫秒。

2. setInterval运行机制

setInterval的运行机制是,将指定的代码移出本次执行,等到下一轮Event Loop时,再检查是否到了指定时间。如果到了,就执行对应的代码;如果不到,就等到再下一轮Event Loop时重新判断。这意味着,setTimeout指定的代码,必须等到本次执行的所有代码都执行完,才会执行。

每一轮Event Loop时,都会将“任务队列”中需要执行的任务,一次执行完。setTimeout和setInterval都是把任务添加到“任务队列”的尾部。因此,它们实际上要等到当前脚本的所有同步任务执行完,然后再等到本次Event Loop的“任务队列”的所有任务执行完,才会开始执行。由于前面的任务到底需要多少时间执行完,是不确定的,所以没有办法保证,setTimeout和setInterval指定的任务,一定会按照预定时间执行。

这一点对于setInterval影响尤其大。

setInterval(function(){
  console.log(2); },1000); (function (){  sleeping(3000); })();

上面的第一行语句要求每隔1000毫秒,就输出一个2。但是,第二行语句需要3000毫秒才能完成,请问会发生什么结果?

结果就是等到第二行语句运行完成以后,立刻连续输出三个2,然后开始每隔1000毫秒,输出一个2。也就是说,setIntervel具有累积效应,如果某个操作特别耗时,超过了setInterval的时间间隔,排在后面的操作会被累积起来,然后在很短的时间内连续触发,这可能或造成性能问题(比如集中发出ajax请求)。

为了进一步理解javascript的单线程模型,请看下面这段伪代码。

function init(){
 { 耗时5ms的某个操作 }  触发mouseClickEvent事件  { 耗时5ms的某个操作 }  setInterval(timerTask,10);  { 耗时5ms的某个操作 } } function handleMouseClick(){  耗时8ms的某个操作 } function timerTask(){  耗时2ms的某个操作 } init();

请问调用init函数后,这段代码的运行顺序是怎样的?

0-15ms:运行init函数。
15-23ms:运行handleMouseClick函数。请注意,这个函数是在5ms时触发的,应该在那个时候就立即运行,但是由于单线程的关系,必须等到init函数完成之后再运行。
23-25ms:运行timerTask函数。这个函数是在10ms时触发的,规定每10ms运行一次,即在20ms、30ms、40ms等时候运行。由于20ms时,JavaScript线程还有任务在运行,因此必须延迟到前面任务完成时再运行。
30-32ms:运行timerTask函数。
40-42ms:运行timerTask函数。

对于setInterval得使用,个人建议是能不用尽量不用。涉及到必须要的定时器,前文已经叙述可以使用两个setTimeout嵌套组合来实现,并且还能规避掉一些问题得发生。涉及到要用它来制作动画( jQuery就使用setInterval来写动画,也是导致其慢原因之一),更建议使用requestAnimationFrame(RAF),或者直接采用CSS来写(如果可以的话)。

requestAnimationFrame比起setTimeout、setInterval的优势主要有两点:

    1. requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧。
    2. 在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量
<think>好的,用户的问题是关于如何在JavaScript中使用clearInterval来取消定时器的示例。我需要先回顾一下JavaScript中的定时器机制,特别是setInterval和clearInterval的用法。 首先,用户可能已经知道setInterval用于创建周期性执行的定时器,但需要了解如何正确停止它。根据引用[1]和[4],clearInterval是用来取消由setInterval创建的定时器的。关键点是必须将setInterval返回的ID传递给clearInterval才能正确清除。 接下来,用户需要具体的示例。我应该提供一个基础的示例,展示如何启动和停止定时器。比如,设置一个每1秒输出一次的定时器,然后在某个条件(比如点击按钮)下清除它。这里要注意变量作用域的问题,定时器ID需要保存在一个可以访问的地方,比如全局变量或组件状态中。 然后,用户可能想知道如何清除所有定时器。引用[2]中提到的方法是通过循环清除可能的ID,但这种方法并可靠,因为ID是递增的,可能清除存在的ID,或者影响其他定时器。需要指出这种方法的潜在问题,并建议正确管理定时器ID。 另外,需要强调及时清除定时器的重要性,如引用[1]所述,避免内存泄漏和性能问题。特别是在单页应用或动态内容中,未清除的定时器可能导致意外行为。 最后,确保回答结构清晰,分步骤说明,代码示例正确,并引用相关参考资料。同时,生成的相关问题需要覆盖用户可能进一步想了解的内容,比如setTimeout与setInterval的区别,或者常见错误。</think>在JavaScript中,使用`clearInterval()`取消定时器的步骤如下: ### 一、基础用法 1. **创建定时器**:通过`setInterval()`获取定时器ID ```javascript let timerId = setInterval(() => { console.log("定时任务执行中..."); }, 1000); ``` 2. **终止定时器**:使用`clearInterval()`传入ID ```javascript clearInterval(timerId); // 立即终止对应定时器[^1] ``` ### 二、完整示例 ```html <button onclick="startTask()">启动定时器</button> <button onclick="stopTask()">终止定时器</button> <script> let timerId; function startTask() { timerId = setInterval(() => { console.log(new Date().toLocaleTimeString()); }, 1000); } function stopTask() { clearInterval(timerId); // 通过按钮点击终止定时器[^4] } </script> ``` ### 三、注意事项 1. **ID管理**:定时器ID是递增整数,建议用变量单独存储而非猜测数值 2. **清除有效性**:对已清除的ID重复调用`clearInterval()`会报错 3. **内存泄漏**:未清除的定时器会持续占用内存,组件销毁时必须清理 ### 四、扩展应用 清除所有定时器的方法(慎用): ```javascript // 通过遍历可能的ID范围强制清除(可能影响其他功能) for(let i = 0; i < 1000; i++){ clearInterval(i); } // 引用自定时器批量清除方案[^2] ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值