什么网站 是cms系统下载地址,石家庄高铁招聘信息网,南宁网站制作策划,外贸自建站类型setImmediate() vs setTimeout() 在 JavaScript 中的区别
在 JavaScript 中#xff0c;setImmediate() 和 setTimeout() 都用于调度任务#xff0c;但它们的工作方式不同。
JavaScript 的异步特性
JavaScript 以其非阻塞、异步行为而闻名#xff0c;尤其是在 Node.js 环境…setImmediate() vs setTimeout() 在 JavaScript 中的区别
在 JavaScript 中setImmediate() 和 setTimeout() 都用于调度任务但它们的工作方式不同。
JavaScript 的异步特性
JavaScript 以其非阻塞、异步行为而闻名尤其是在 Node.js 环境中。如果你曾经参与过涉及定时器或回调的项目你可能遇到过 setTimeout()甚至 setImmediate()。乍一看这两个函数似乎做的是同一件事——调度任务以便稍后运行。但如果你曾经一起运行它们你可能会注意到一些有趣的行为。
尽管它们的目的相似但 setImmediate() 和 setTimeout() 在底层的操作方式不同。如果你想知道为什么 setImmediate() 回调似乎一个接一个地运行而 setTimeout() 回调则是间隔开的本指南将为你解析其中的原因。
这不仅仅是 JavaScript 的一个怪癖它与 Node.js 如何管理异步任务密切相关。理解这两个函数之间的差异将帮助你更好地控制代码的时间和执行顺序这对于大型应用程序尤其重要因为即使是时间上的微小失误也可能导致难以发现的错误。
我们将深入探讨事件循环它如何处理这些定时器以及为什么在一起使用它们时事情并不总是按预期发生。到最后你将更清楚地了解何时使用 setTimeout() 或 setImmediate()以满足你所需的时间行为。
行为差异
setImmediate(() {console.log(setImmediate 1);
});setTimeout(() {console.log(setTimeout 1);
}, 0);setTimeout(() {console.log(setTimeout 2);
}, 0);setImmediate(() {console.log(setImmediate 2);
});当你运行这段代码时你可能期望 setTimeout 回调按定义的顺序执行然后是 setImmediate 回调。但你在控制台中看到的是
setTimeout 1
setImmediate 1
setImmediate 2
setTimeout 2如果这让你感到困惑不要担心。让我们解开其中的原因。
事件循环
要理解这一点我们需要快速了解 Node.js 如何管理异步操作。Node.js 的异步特性核心是事件循环。
在 Node.js 中事件循环处理不同的阶段每个阶段负责执行某些类型的回调。它帮助管理非阻塞任务确保函数可以异步执行。在这些阶段中有不同的队列。对于本次讨论有两个队列是重要的
宏任务队列这是 setTimeout 和 setImmediate 等任务所在的地方。微任务队列这是 promises (Promise.then()) 和 process.nextTick() 回调所在的地方。
事件循环的工作原理
要理解 setTimeout() 和 setImmediate() 的工作原理我们需要看看 Node.js 中的事件循环。事件循环允许 Node.js 处理异步代码。它在不同的阶段处理不同类型的操作每个阶段负责特定的任务。 ┌───────────────────────────┐
┌─│ timers │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ pending callbacks │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ idle, prepare │
│ └─────────────┬─────────────┘ ┌───────────────┐
│ ┌─────────────┴─────────────┐ │ incoming: │
│ │ poll │─────┤ connections, │
│ └─────────────┬─────────────┘ │ data, etc. │
│ ┌─────────────┴─────────────┐ └───────────────┘
│ │ check │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
└──┤ close callbacks │└───────────────────────────┘定时器阶段这是处理 setTimeout() 回调的地方。即使是 0 毫秒的延迟它们也要等到下一次循环迭代才能执行。待处理回调阶段处理已完成的 I/O 事件但我们的示例中没有所以跳过这个阶段。检查阶段setImmediate() 回调在这里运行。它们在 I/O 任务之后立即执行但在 setTimeout() 回调之前。轮询阶段处理新的传入 I/O 操作如文件读取或网络请求。如果没有 I/O事件循环会跳过这个阶段。下一次循环迭代在检查阶段之后事件循环回到处理下一个定时器阶段在那里 setTimeout() 回调最终运行。
setTimeout() 的 0 延迟
当你使用 setTimeout() 并设置延迟为 0 时你实际上是在告诉 Node.js 在当前操作完成后尽快运行回调。然而重要的是要记住“尽快”仍然取决于事件循环的阶段。
setTimeout(() {console.log(setTimeout 1 with 0 delay);
}, 0);setImmediate(() {console.log(setImmediate 1);
});setTimeout(() {console.log(setTimeout 2 with 0 delay);
}, 0);输出结果
setTimeout 1 with 0 delay
setImmediate 1
setTimeout 2 with 0 delay即使延迟为 0setTimeout() 回调仍然需要等待定时器阶段的下一次循环因此不会立即运行。相反它被放置在宏任务队列中以便在下一个可用机会执行。
setImmediate()
另一方面setImmediate() 设计用于在 I/O 事件完成后执行回调在同一事件循环迭代中。这意味着 setImmediate() 回调在额外的定时器如 setTimeout()执行之前被处理特别是在没有 I/O 的情况下。
在我们的示例中由于没有 I/O 发生两个 setImmediate() 回调会一个接一个地执行然后才轮到第二个 setTimeout() 回调。
为什么 setImmediate 回调会一起运行
相同的事件循环周期两个 setImmediate 调用在事件循环的同一个周期或循环中被放置到宏任务队列中。Node.js 按顺序处理这些任务。优先于 setTimeout()即使 setTimeout() 设定了 0 延迟这也不保证立即执行。setImmediate() 回调在当前周期中优先于 setTimeout() 任务。
现实世界的类比
想象一下在餐馆点餐和饮料。
你点了一道菜代表 setTimeout(0)。厨师将其添加到订单队列中一旦准备好就会送达。同时你要了一杯水setImmediate()由于它快速且容易准备服务员会在你的食物完成之前立即送达。
在这个类比中水快速任务首先被处理即使两个订单几乎同时下达。菜稍微复杂一些稍后送达。
这种情况总是发生吗
不一定。setImmediate() 和 setTimeout() 的行为可能取决于代码中发生的其他异步操作。如果有 I/O 操作执行顺序可能会改变因为 setImmediate() 只会在 I/O 事件完成后运行。
const fs require(fs);fs.readFile(example.txt, () {setTimeout(() {console.log(setTimeout after I/O);}, 0);setImmediate(() {console.log(setImmediate after I/O);});
});输出结果
setImmediate after I/O
setTimeout after I/O在这种情况下setImmediate() 总是在 setTimeout() 之前运行因为事件循环在 I/O 回调之后优先处理 setImmediate()。
当没有 I/O 事件时两个 setImmediate() 回调会一个接一个地运行然后才轮到 setTimeout() 回调。
process.nextTick() 和 Promises
以下示例展示了 Node.js 中各种异步操作的处理方式
setTimeout(() {console.log(setTimeout);
}, 0);setImmediate(() {console.log(setImmediate);
});Promise.resolve().then(() {console.log(Promise then);
});process.nextTick(() {console.log(process.nextTick);
});输出结果
process.nextTick
Promise then
setTimeout
setImmediateprocess.nextTick()这将在任何其他任务之前运行甚至在微任务如 Promises之前。Promise.then()这是一个微任务因此它在当前操作之后但在宏任务如 setTimeout() 和 setImmediate()之前运行。setTimeout()在微任务处理完之后运行。setImmediate()尽管它类似于 setTimeout()但它在事件循环周期的后期运行在当前 I/O 操作之后。
Node.js 的异步行为有时可能会令人困惑特别是在处理 setTimeout() 和 setImmediate() 时。关键是理解事件循环以及任务在不同阶段的调度方式。
setImmediate() 在 I/O 事件之后和当前事件循环周期内运行。setTimeout() 在指定的延迟之后运行即使延迟为 0它也会为下一次事件循环迭代调度任务。当没有 I/O 操作时setImmediate() 会在下一个 setTimeout() 之前连续执行。
理解这些差异有助于你精确控制代码的运行时间这在高性能应用程序中至关重要因为时间和效率非常重要。