MST
星途 面试题库

面试题:JavaScript中事件机制的事件循环原理

请详细阐述JavaScript事件循环(Event Loop)的工作原理,包括调用栈(Call Stack)、任务队列(Task Queue)以及它们之间是如何协作的,并举例说明这一机制在处理异步任务时的表现。
31.6万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

JavaScript事件循环工作原理

  1. 调用栈(Call Stack)
    • 调用栈是一种数据结构,用于记录函数调用的顺序。当JavaScript引擎执行代码时,每调用一个函数,就将该函数添加到调用栈的栈顶;函数执行完毕后,从栈顶移除。例如:
function add(a, b) {
    return a + b;
}

function multiply(c, d) {
    let result = add(c, d);
    return result * 2;
}

multiply(3, 4);

在上述代码中,首先调用multiply函数,multiply函数被压入调用栈。然后在multiply函数内部调用add函数,add函数又被压入调用栈。add函数执行完毕返回结果后,从调用栈移除。接着multiply函数继续执行并返回结果,最后multiply函数也从调用栈移除。

  1. 任务队列(Task Queue)

    • 任务队列用于存放异步任务的回调函数。当异步操作(如setTimeoutPromise等)完成时,其回调函数不会立即进入调用栈执行,而是被放入任务队列。任务队列可以理解为一个先进先出(FIFO)的队列,新的回调函数不断被添加到队列末尾。
  2. 事件循环(Event Loop)

    • 事件循环负责协调调用栈和任务队列。它不断地检查调用栈是否为空,如果调用栈为空,就从任务队列中取出一个任务(即回调函数),将其压入调用栈执行。这个过程会不断重复,这就是事件循环的工作机制。

处理异步任务时的表现举例

  1. setTimeout示例
console.log('Start');
setTimeout(() => {
    console.log('Timeout callback');
}, 0);
console.log('End');
  • 首先,console.log('Start')被执行,打印Start
  • 然后setTimeout函数被调用,它是一个异步操作,其回调函数并不会立即执行,而是被放入任务队列。
  • 接着console.log('End')被执行,打印End
  • 此时调用栈为空,事件循环开始工作,从任务队列中取出setTimeout的回调函数,压入调用栈执行,打印Timeout callback
  1. Promise示例
console.log('Start');
Promise.resolve().then(() => {
    console.log('Promise callback');
});
console.log('End');
  • console.log('Start')执行,打印Start
  • Promise.resolve()返回一个已解决的Promise,其.then回调函数被放入任务队列。
  • console.log('End')执行,打印End
  • 调用栈为空后,事件循环从任务队列取出Promise的.then回调函数压入调用栈执行,打印Promise callback。需要注意的是,Promise的回调属于微任务,微任务队列的优先级高于宏任务队列(setTimeout的回调属于宏任务),在事件循环的一次循环中,会先清空微任务队列,再处理宏任务队列。