0Pricing
JavaScript Academy · 课时

宏任务与任务队列

了解计时器和输入输出操作如何被调度。

宏任务与任务队列 是 CoddyKit 上的免费 JavaScript Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 JavaScript Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 JavaScript Academy 课程共包含 4 节课。

什么是宏任务

宏任务(也称为任务)是一个稍后执行的工作单元,会在当前同步代码完成后运行。setTimeout 回调就是典型示例。

宏任务会在调用栈为空之前一直等待于任务队列中。

setTimeout 推迟工作

setTimeout 会注册一个稍后运行的回调。即使延迟为 0,它也会在当前所有同步代码之后运行。

console.log('first');
setTimeout(() => console.log('third (timeout)'), 0);
console.log('second');

任务队列

定时器触发后,其回调会被放入任务队列。事件循环只有在调用栈为空时,才会从该队列取出一个任务,将其执行完毕,然后再次检查。

console.log('sync start');
setTimeout(() => console.log('task 1'), 0);
setTimeout(() => console.log('task 2'), 0);
console.log('sync end');

任务按照入队顺序运行

延迟相同的任务会按照安排顺序运行。任务队列遵循 FIFO:先进先出。

setTimeout(() => console.log('A'), 0);
setTimeout(() => console.log('B'), 0);
setTimeout(() => console.log('C'), 0);
console.log('sync');

延迟是最短时间,而非准确时间

您传入的延迟是回调可以运行前等待的最短时间。只有调用栈清空且更早的任务完成后,回调才会真正运行,因此实际时间可能更晚。

setTimeout(() => console.log('100ms'), 100);
setTimeout(() => console.log('0ms'), 0);
console.log('synchronous runs first');

按延迟排序

不同的延迟会改变执行顺序:较短的延迟会更早达到可运行条件,因此通常会先于较长延迟运行,无论安排顺序如何。

setTimeout(() => console.log('50'), 50);
setTimeout(() => console.log('10'), 10);
setTimeout(() => console.log('30'), 30);
console.log('start');

每轮循环执行一个任务

事件循环每轮恰好运行一个宏任务,然后在下一轮之前执行其他工作。这样可以让系统在任务之间保持响应。

console.log('1');
setTimeout(() => {
  console.log('2');
  setTimeout(() => console.log('4'), 0);
}, 0);
setTimeout(() => console.log('3'), 0);

嵌套定时器会稍后入队

在一个任务内部安排的定时器会排在已经等待的任务之后加入队列,因此会在更晚的一轮循环中运行。

setTimeout(() => {
  console.log('outer');
  setTimeout(() => console.log('inner nested'), 0);
}, 0);
setTimeout(() => console.log('sibling'), 0);

setInterval 也是宏任务

setInterval 会安排一个重复执行的宏任务。这里我们运行几次迭代,然后使用 clearInterval 停止它,以限制输出量。

let count = 0;
const id = setInterval(() => {
  count++;
  console.log('tick ' + count);
  if (count === 3) clearInterval(id);
}, 10);
console.log('interval scheduled');

同步代码始终优先

无论延迟多么短,每个宏任务都会排在当前运行中的所有同步代码之后。必须先清空调用栈。

setTimeout(() => console.log('macrotask'), 0);
for (let i = 1; i <= 3; i++) console.log('sync ' + i);
console.log('done sync');

宏任务为何重要

宏任务让您可以推迟工作,而不会造成阻塞。将繁重的工作拆分为按时间安排的多个小块,可以让应用保持响应。但宏任务并不是最高优先级:微任务(承诺机制)会在下一个宏任务之前运行,您将在下一部分看到这一点。

console.log('schedule');
setTimeout(() => console.log('runs after sync'), 0);
console.log('still sync');

快速检查

setTimeout(cb, 0) 的回调什么时候运行?

回顾:宏任务

您已经学会了延迟工作的安排方式:

  • 宏任务(setTimeout、setInterval)会在任务队列中等待。
  • 队列遵循 FIFO;事件循环每轮运行一个任务。
  • 延迟只是最短等待时间,同步代码始终先运行。
  • 微任务具有更高优先级,您将在下一部分探索这一点。

常见问题解答

「宏任务与任务队列」课时是免费的吗?

是的 — 「宏任务与任务队列」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 JavaScript Academy 课程的其余内容,请升级到 CoddyKit PRO。 JavaScript Academy 课程共包含 4 节课。

「宏任务与任务队列」这节课中我会学到什么?

了解计时器和输入输出操作如何被调度。 你通过在浏览器中直接运行的动手代码来练习 JavaScript Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 JavaScript Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 JavaScript Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「宏任务与任务队列」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 JavaScript Academy 课中编写并运行代码吗?

能。每节 JavaScript Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 调用栈
  2. 宏任务与任务队列
  3. 微任务与 Promise
  4. queueMicrotask 与执行顺序
← 返回 JavaScript Academy