Skip to content

定时器

元信息

  • 目标:用 setTimeout/setInterval 建立"稍后执行"的异步体感——代码顺序≠执行顺序;观察 alert 等阻塞操作如何让定时器排队,理解 js 单线程下异步执行的不确定性
  • 关键概念:定时器、系统事件、一次性/循环事件、异步执行、代码顺序与执行顺序、阻塞、单线程
  • 关联阶段:cp3
  • 常见误区:以为 setTimeout(fn, 3000) 保证 3 秒整执行(到点后还需等主线程空闲);以为代码写在后面就后执行(回调执行顺序与代码顺序无关);把"输出 12 还是 21"当浏览器 bug(异步系统执行顺序本就不确定)

什么是定时器?

定时器是一种系统事件,由运行环境实现和触发。

通过定时器,开发者可以不依赖于用户的操作而自动调用执行某些代码

js中支持两种定时器事件:一次性事件、循环事件

定时器示例

<!DOCTYPE html>
<html>
<head>
  <title>Parcel Sandbox</title>
  <meta charset="UTF-8" />
  <link rel="stylesheet" href="/styles.css" />
</head>
<body>
  <h1>Hello world</h1>
</body>
</html>

输出结果是:
"hello from console"
"hello from window"

异步执行

  • 代码顺序:在代码中的前后顺序,反映了编辑时的两段代码之间的顺序。
  • 执行顺序:在运行时的顺序。对于支持异步执行的系统,执行顺序是不确定的。

js定时器允许函数引用作为它的参数,使得函数的声明和执行分离为两个阶段。

  • setTimeout(alertFunc, 3000)本身是函数声明和执行为一体的,它与后面的console.log("hello from console")是同步关系
  • alertFunc则分为声明和调用两个部分。其中调用过程是隐式的, 它由系统来执行,调用时点则取决于定时器函数的设置。

也就是说alertFunc()的执行顺序与它所在的代码顺序无关,称之为异步执行。

被阻塞的定时器

<!DOCTYPE html>
<html>
<head>
  <title>Parcel Sandbox</title>
  <meta charset="UTF-8" />
  <link rel="stylesheet" href="/styles.css" />
</head>
<body>
  <h1>Hello world</h1>
</body>
</html>
  • 当"我是窗口主线程"的对话框未被用户点击OK按钮之前,两个定时器均不会被执行(被阻塞),即使定时时间已超时。
  • 假如用户先等足3秒之后,再点击对话框的OK按钮, 则两个定时器处理函数会立即被执行,似乎这些定时器已排队到位,但等待前面的代码被执行完毕。
  • 进一步观察发现:alert这一类涉及操作系统子窗口的函数被执行时,浏览器主窗口将无法接收用户的输入,其代码也停止执行;故这类包含窗口函数的代码是典型的阻塞式操作。也因此应当避免使用alert这类功能

异步执行:不确定的运行时顺序

import "./styles.css";

document.getElementById("app").innerHTML = `
<h1>Hello world</h1>
`;

上述结果是12还是21,取决于浏览器所在机器执行循环的实际时间

如果你希望确保输出的是12,该如何做? 在后续的ajax中,我们将再次讨论异步

同步与异步、串行与并行这两组词之间的区别?

教程

参考阅读