这是我参与8月更文挑战的第19天,活动详情查看: 8月更文挑战
序言
相信很多人都有用过setTimeout 和setInterval但是他们之间的差异和细节你真的知道吗,JS是如何进行期中的任务调度的?今天我们就来了解一下期中的奥秘,以便日后根据场景选择合适的方法。
setTimeout
使用方法:
let timerId = setTimeout(function(){},time, [arg1], [arg2], ...)
参数说明:
function :执行函数,延迟事件到了,执行的函数操作。
time:执行的时间,毫秒为单位(1000毫秒=1秒),默认值为0。
arg1,arg2 : 要传入的执行函数的参数列表。
我们来看几个实例
在下面这个示例中,sayHi() 方法会在 1 秒后执行:
function sayHi() {
alert('Hello');
}
setTimeout(sayHi, 1000);
带参数的情况:
function sayHi(phrase, who) {
alert( phrase + ', ' + who );
}
setTimeout(sayHi, 1000, "Hello", "coolFish"); // Hello, coolFish
要注意的是,这里传入的是函数的引用,而不是函数的调用。还有一种内联的写法。
setTimeout(()=>{
alert('Hello');
},1000)
clearTimeout取消计时
setTimeout 在调用时会返回一个“定时器标识符”,在我们的例子中是 timerId,我们可以使用它来取消执行。
let endTime = true
let timerId = setTimeout(() => alert("never happens"), 1000);
alert(timerId); // 定时器标识符
if(endTime){
clearTimeout(timerId);
alert(timerId); // 还是这个标识符(并没有因为调度被取消了而变成 null)
}
从 alert 的输出来看,在浏览器中,定时器标识符是一个数字。在其他环境中,可能是其他的东西。例如 Node.js 返回的是一个定时器对象,这个对象包含一系列方法。
setInterval
setInterval 方法和 setTimeout 的语法相同
let timerId = setInterval(function(){},time, [arg1], [arg2], ...)
所有参数的意义也是相同的。不过与 setTimeout 只执行一次不同,setInterval 是每间隔给定的时间周期性执行。也就是说setTimeout更像一个定时器,到了事件触发,而setInterval更像一个计时器,每到一定时间触发。 想要阻止后续调用,我们需要调用 clearInterval(timerId)。 我们来看个例子
// 每 2 秒重复一次
let timerId = setInterval(() => alert('coolFish'), 2000);
// 10 秒之后停止
setTimeout(() => { clearInterval(timerId); alert('stop'); }, 10000);
上例的结果为:弹出5次 coolFish ,然后 stop,需要注意的是,如果10s后再点击确认弹窗,那么会连续直接出现5次,这是因为在大多数浏览器中,包括 Chrome 和 Firefox,在显示 alert/confirm/prompt 弹窗时,内部的定时器仍旧会继续计时。所以当你不点击,他也在计时触发,在你关闭第一个的时候,第二个会立马显示。 解决这种问题,我们可以使用嵌套的 setTimeout 。
嵌套的 setTimeout
嵌套的setTimeout 就是用setTimeout 嵌套来模仿setInterval 的操作,但是他比 setInterval灵活,采用这种方式,可以根据当前执行结果来决定如何调度下一次。
let delay = 5000;
let timerId = setTimeout(function request() {
...发送请求...
if (request failed due to server overload) {
// 下一次执行的间隔是当前的 2 倍
delay *= 2;
}
timerId = setTimeout(request, delay);
}, delay);
上例是一个向服务器请求数据的一个服务,每一次发送请求,服务器返回的结果是错误的话,就隔双倍的实际再请求一次,防止过多的无效请求。
最重要的是: 嵌套的 setTimeout 能够精确地设置两次执行之间的延时,而 setInterval 却不能。 对 setInterval 而言,内部的调度程序会每间隔 100 毫秒执行一次 func(),但是执行 func() 需要时间,这些时间会时方法执行的间隔缩短,造成误差。 嵌套的 setTimeout 就能确保延时的固定(这里是 100 毫秒)。