返回

JS进阶之旅:深入探索执行机制

前端

JavaScript执行机制:精妙的运作之道

前言

还记得毕业那会刚接触JavaScript的时候,觉得这门语言很奇怪。和上学时学的C++相比,虽然写法差异没那么大,但运行逻辑非常不一样。比如拷贝下面的JS代码,在浏览器控制台中运行:

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

结果是:

1
3
2

这让我百思不得其解,为什么setTimeout明明设置了0毫秒的延迟,却依然排在console.log('3');之后执行?带着这个疑问,我开始了对JavaScript执行机制的探索之旅。

执行机制概览

JavaScript的执行机制主要由以下几个部分组成:

  • 调用栈(Call Stack) :调用栈是一个先进后出的(LIFO)栈,用于存储当前正在执行的函数。当一个函数被调用时,它会被压入调用栈,当函数执行完毕后,它会被弹出调用栈。
  • 事件循环(Event Loop) :事件循环是一个无限循环,它不断地从调用栈中取出函数并执行。当调用栈为空时,事件循环会等待新的事件发生,然后将相应的函数压入调用栈并执行。
  • 宏任务(Macro Task) :宏任务是需要花费较长时间才能完成的任务,比如setTimeoutsetIntervalI/O操作等。宏任务会被放入宏任务队列中,由事件循环负责执行。
  • 微任务(Micro Task) :微任务是需要花费极短时间就能完成的任务,比如PromiseMutationObserver等。微任务会被放入微任务队列中,由事件循环负责执行。

执行机制运作原理

JavaScript的执行机制运作原理如下:

  1. 当一个脚本被加载到浏览器中时,它会被解析成抽象语法树(AST)。
  2. AST会被解释器解释成字节码。
  3. 字节码会被执行引擎执行。
  4. 执行引擎会将函数压入调用栈。
  5. 执行引擎会执行函数中的代码。
  6. 当函数执行完毕后,它会被弹出调用栈。
  7. 事件循环会从调用栈中取出函数并执行。
  8. 当调用栈为空时,事件循环会等待新的事件发生,然后将相应的函数压入调用栈并执行。
  9. 当宏任务队列中有宏任务时,事件循环会将宏任务取出并执行。
  10. 当微任务队列中有微任务时,事件循环会将微任务取出并执行。

深入理解事件循环

事件循环是JavaScript执行机制的核心,它负责协调函数的执行顺序。事件循环会不断地从调用栈中取出函数并执行,当调用栈为空时,事件循环会等待新的事件发生,然后将相应的函数压入调用栈并执行。

事件循环的运作过程如下:

  1. 事件循环会从调用栈中取出一个函数并执行。
  2. 函数执行完毕后,它会被弹出调用栈。
  3. 事件循环会检查宏任务队列,如果有宏任务,则将宏任务取出并执行。
  4. 事件循环会检查微任务队列,如果有微任务,则将微任务取出并执行。
  5. 如果调用栈为空,并且宏任务队列和微任务队列都为空,则事件循环会等待新的事件发生。
  6. 当新的事件发生时,事件循环会将相应的函数压入调用栈并执行。

理解宏任务和微任务

宏任务和微任务都是需要事件循环执行的任务,但它们之间存在一些区别。

  • 宏任务 需要花费较长时间才能完成,比如setTimeoutsetIntervalI/O操作等。宏任务会被放入宏任务队列中,由事件循环负责执行。
  • 微任务 需要花费极短时间就能完成,比如PromiseMutationObserver等。微任务会被放入微任务队列中,由事件循环负责执行。

宏任务和微任务的执行顺序如下:

  1. 事件循环会从调用栈中取出函数并执行。
  2. 函数执行完毕后,它会被弹出调用栈。
  3. 事件循环会检查微任务队列,如果有微任务,则将微任务取出并执行。
  4. 事件循环会检查宏任务队列,如果有宏任务,则将宏任务取出并执行。
  5. 如果调用栈为空,并且宏任务队列和微任务队列都为空,则事件循环会等待新的事件发生。
  6. 当新的事件发生时,事件循环会将相应的函数压入调用栈并执行。

宏任务和微任务的应用场景

宏任务和微任务在不同的场景下都有各自的应用场景。

  • 宏任务 通常用于需要花费较长时间才能完成的任务,比如setTimeoutsetIntervalI/O操作等。
  • 微任务 通常用于需要花费极短时间就能完成的任务,比如PromiseMutationObserver等。

总结

JavaScript的执行机制是一个复杂且精妙的系统,它负责协调函数的执行顺序。通过理解执行机制的运作原理,我们可以更好地理解JavaScript的运行逻辑,并编写出更加高效的代码。