返回

JavaScript 函数执行时机:异步和同步代码的执行顺序详解

前端

JavaScript 函数执行时机:掌握执行顺序和作用域

JavaScript 是一种单线程语言,这意味着它的代码按顺序一行一行执行,不会并行处理。理解 JavaScript 函数的执行时机至关重要,因为它决定了代码如何运行以及变量如何作用。

异步执行的 setTimeout() 函数

在 JavaScript 中,setTimeout() 函数用于指定某个函数在指定时间后执行。该函数接受两个参数:要执行的函数和延迟时间(以毫秒为单位)。

setTimeout(function() {
  console.log("Hello, world!");
}, 0);

console.log("This will be printed first.");

在这段代码中,setTimeout() 函数将匿名函数安排在 0 毫秒后执行。这意味着它将在当前执行栈中的所有同步代码执行完毕后立即执行。

宏任务和微任务队列

JavaScript 有两个队列来管理任务的执行:宏任务队列和微任务队列。宏任务队列包含需要在执行栈中运行的任务,而微任务队列包含在当前执行栈中运行的任务。

事件循环

JavaScript 引擎通过不断轮询宏任务和微任务队列来执行代码。它首先执行宏任务队列中的所有任务,然后执行微任务队列中的所有任务,然后再次执行宏任务队列,依此类推。

setTimeout() 和事件循环

当 JavaScript 引擎遇到 setTimeout() 时,它会将匿名函数添加到宏任务队列中。一旦当前执行栈中的所有同步代码执行完毕,宏任务队列将被轮询,并且匿名函数将被执行。

代码执行顺序

因此,给定示例的执行顺序如下:

  1. "This will be printed first." 打印到控制台。
  2. 匿名函数被添加到宏任务队列中。
  3. 执行栈中的所有同步代码完成执行。
  4. 宏任务队列被轮询,匿名函数被执行。
  5. "Hello, world!" 打印到控制台。

变量作用域

在 JavaScript 中,函数的作用域链决定了它可以访问哪些变量。匿名函数的作用域链包括它声明的环境中的所有变量。

var message = "Hello, world!";

setTimeout(function() {
  console.log(message);
}, 0);

在这种情况下,匿名函数可以访问 message 变量,因为 message 在其作用域链中。即使 message 在匿名函数执行之前被重新分配,匿名函数仍会访问其原始值。

结论

理解 JavaScript 函数的执行时机对于编写健壮、可维护的代码至关重要。通过理解 setTimeout() 函数如何在宏任务队列和事件循环中工作,您可以控制代码的执行顺序和变量的作用域。