第九章 JavaScript 异步编程专题 定时器

126 阅读4分钟

9 异步编程专题

什么是异步编程,直观的说就是代码的执行顺序和书写顺序可能不一致,因此需要使用一些特殊的技术来处理异步操作的结果,如回调函数、Promise、async/await 等,主要目的是在不阻塞主线程的情况下,让程序异步执行某些操作,从而提高程序的响应速度和性能。本章就来讲解异步编程相关的知识。

9.1 定时器

setTimeout 和 clearTimeout

setTimeout 函数可以用来延迟一段时间后执行指定的代码,它接受两个参数:第一个参数是一个函数,表示要执行的代码;第二个参数是一个数字,表示要延迟的时间(单位为毫秒)。 例如,下面的代码会在 1 秒后输出一条消息:

let timeoutId = setTimeout(function() {
  console.log('1 秒已过');
}, 1000);

clearTimeout 函数可以用来取消一个正在执行的延迟任务,它接受一个参数,即要取消的任务的 ID。这个 ID 是在调用 setTimeout 函数时返回的,你可以将它保存在一个变量中,然后在需要取消任务时传入 clearTimeout 函数。 例如,下面的代码会在 1 秒后输出一条消息,但是在 500 毫秒时取消了这个任务:

let timeoutId = setTimeout(function() {
  console.log('1 秒已过');
}, 1000);

setTimeout(function() {
  clearTimeout(timeoutId);
  console.log('任务已取消');
}, 500);

需要注意的是,setTimeout 函数并不是精确的定时器,它的执行时间可能会受到一些因素的影响,例如当前系统负载、其他任务的执行时间等。 如果省略 setTimeout 的第二个参数,那么会默认设置为 0,但是这并不是 JavaScript 标准的行为。实际上,根据标准规定,如果省略第二个参数,setTimeout 应该会使用一个默认的值。不同的浏览器可能会有不同的默认值,但并不一定是 0。注意即使设置了0,回调函数仍然不会立刻执行,还是会异步执行,只是尽可能早的执行。 除了前两个参数,setTimeout 方法还接受多个可选的参数,它们将被依次传递给回调函数。从第三个参数开始,可以传递任意多个参数,它们将被依次传递给回调函数,作为回调函数的参数。 以下是一个使用 setTimeout 传递参数的示例:

function greet(name, message) {
  console.log(`${name}, ${message}`);
}
setTimeout(greet, 1000, 'John', 'how are you?');

在这个例子中,setTimeout 方法延迟了1000毫秒,然后调用 greet 函数,并将 'John' 和 'how are you?' 作为参数传递给它。因此,在1000毫秒后,greet 函数将会被调用,并打印以下内容: John, how are you? 注意,如果需要传递多个参数给回调函数,可以在第一个参数(回调函数)之后列出所有参数。这些参数将按照它们在 setTimeout 中的顺序传递给回调函数。

setInterval和clearInterval

setInterval 函数与 setTimeout 函数的用法基本相同,不同之处在于它会按照指定的时间间隔无限次地执行某个任务,直到被取消。其语法格式如下: setInterval(function, milliseconds, param1, param2, ...) 其中,第一个参数 function 是要执行的函数,第二个参数 milliseconds 是每次执行之间的时间间隔,后续的参数是传递给函数的参数。 与 setTimeout 类似,setInterval 函数也会返回一个唯一的 ID,可以使用 clearInterval 函数来取消定时执行。 需要注意的是,虽然 setInterval 函数指定的时间间隔是精确的,但是如果在任务执行的过程中发生了阻塞或者页面失去了焦点,就有可能导致任务的执行时间延迟或者不准确。 看下面一个综合使用的例子:

function printTime() {
  const now = new Date();
console.log(`${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`);
}
const intervalId = setInterval(printTime, 1000);
setTimeout(() => {
  clearInterval(intervalId);
}, 5000);

该例子中,先使用 setInterval 方法周期性地调用 printTime 函数,并将返回的 intervalId 存储到变量 intervalId 中。然后,使用 setTimeout 方法在 5 秒后调用一个函数,该函数会调用 clearInterval 方法并传入 intervalId,从而停止周期性调用。这样,前面的打印操作会在 5 秒后停止。