持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情
有时我们并不想立即执行一个函数,而是等待特定一段时间之后再执行。这就是所谓的“计划调用(scheduling a call)”。
目前有两种方式可以实现:
setTimeout允许我们将函数推迟到一段时间间隔之后再执行。setInterval允许我们重复运行一个函数,从一段时间间隔之后开始运行,之后以该时间间隔连续重复运行该函数。
这两个方法并不在 JavaScript 的规范中。但是大多数运行环境都有内建的调度程序,并且提供了这些方法。目前来讲,所有浏览器以及 Node.js 都支持这两个方法。
setTimeout
语法:
let timerId = setTimeout(func|code, [delay], [arg1], [arg2], ...)
参数说明:
-
func|code想要执行的函数或代码字符串。 一般传入的都是函数。由于某些历史原因,支持传入代码字符串,但是不建议这样做。
-
delay执行前的延时,以毫秒为单位(1000 毫秒 = 1 秒),默认值是 0;
-
arg1,arg2…要传入被执行函数(或代码字符串)的参数列表(IE9 以下不支持)
例如,在下面这个示例中,sayHi() 方法会在 1 秒后执行:
function sayHi() {
alert('Hello');
}
setTimeout(sayHi, 1000);
带参数的情况:
function sayHi(phrase, who) {
alert( phrase + ', ' + who );
}
setTimeout(sayHi, 1000, "Hello", "John"); // Hello, John
如果第一个参数位传入的是字符串,JavaScript 会自动为其创建一个函数。
所以这么写也是可以的:
setTimeout("alert('Hello')", 1000);
但是,不建议使用字符串,我们可以使用箭头函数代替它们,如下所示:
setTimeout(() => alert('Hello'), 1000);
传入一个函数,但不要执行它
新手开发者有时候会误将一对括号 () 加在函数后面:
// 错的!
setTimeout(sayHi(), 1000);
这样不行,因为 setTimeout 期望得到一个对函数的引用。而这里的 sayHi() 很明显是在执行函数,所以实际上传入 setTimeout 的是 函数的执行结果。在这个例子中,sayHi() 的执行结果是 undefined(也就是说函数没有返回任何结果),所以实际上什么也没有调度。
用 clearTimeout 来取消调度
setTimeout 在调用时会返回一个“定时器标识符(timer identifier)”,在我们的例子中是 timerId,我们可以使用它来取消执行。
取消调度的语法:
let timerId = setTimeout(...);
clearTimeout(timerId);
在下面的代码中,我们对一个函数进行了调度,紧接着取消了这次调度(中途反悔了)。所以最后什么也没发生:
let timerId = setTimeout(() => alert("never happens"), 1000);
alert(timerId); // 定时器标识符
clearTimeout(timerId);
alert(timerId); // 还是这个标识符(并没有因为调度被取消了而变成 null)
从 alert 的输出来看,在浏览器中,定时器标识符是一个数字。在其他环境中,可能是其他的东西。例如 Node.js 返回的是一个定时器对象,这个对象包含一系列方法。
我再重申一遍,这些方法没有统一的规范定义,所以这没什么问题。
针对浏览器环境,定时器在 HTML5 的标准中有详细描述,详见 timers section。
setInterval
setInterval 方法和 setTimeout 的语法相同:
let timerId = setInterval(func|code, [delay], [arg1], [arg2], ...)
所有参数的意义也是相同的。不过与 setTimeout 只执行一次不同,setInterval 是每间隔给定的时间周期性执行。
想要阻止后续调用,我们需要调用 clearInterval(timerId)。
下面的例子将每间隔 2 秒就会输出一条消息。5 秒之后,输出停止:
// 每 2 秒重复一次
let timerId = setInterval(() => alert('tick'), 2000);
// 5 秒之后停止
setTimeout(() => { clearInterval(timerId); alert('stop'); }, 5000);
alert 弹窗显示的时候计时器依然在进行计时
在大多数浏览器中,包括 Chrome 和 Firefox,在显示 alert/confirm/prompt 弹窗时,内部的定时器仍旧会继续“嘀嗒”。
所以,在运行上面的代码时,如果在一定时间内没有关掉 alert 弹窗,那么在你关闭弹窗后,下一个 alert 会立即显示。两次 alert 之间的时间间隔将小于 2 秒。