本文详细解析JavaScript的单线程异步非阻塞执行模型,涵盖调用栈、事件循环、任务队列及Web API的核心机制。深入探讨宏任务与微任务的执行顺序、递归栈溢出风险,以及V8引擎在浏览器与Node.js中的角色,帮助开发者理解异步代码的执行流程。
JavaScript执行模型概述
详解JavaScript执行模型
引言
JavaScript被设计为一种单线程、异步且非阻塞的并发语言。这种并发能力主要依赖于调用栈(Call Stack)、事件循环(Event Loop)、回调队列(Callback Queue,有时也称为任务队列 Task Queue)以及与具体运行环境相关的API共同协作实现。
概念
调用栈机制与递归风险
调用栈 Call Stack
调用栈是一种后进先出(LIFO)的数据结构,用于管理函数的执行状态,其内部存储单元为函数帧。当JavaScript中调用一个函数时,该函数会被压入栈中;若函数内部再次调用其他函数,新函数将被压入栈顶。直到栈顶函数内部不再包含更多调用,它将以单线程方式执行完毕并出栈,直至最后一个函数帧离开栈。JavaScript所强调的单线程特性,指的就是调用栈的这种单线程运行模式。
function multiply(a, b) {
return a * b;
}
function square(n) {
return multiply(n, n)
}
function printSquare(n) {
console.log(square(n));
}
printSquare(4);
首先调用栈压入main(),扫描到printSquare()函数调用调用栈压入printSquare(4),printSquare函数内部调用square(n)该函数被压入栈,同理multiply(n, n)函数也被压入栈且没有更多调用,JavaScript引擎开始执行栈顶函数multiply(n, n)返回结果并出栈,以此类推直到main()函数出栈。
调用栈存在一种异常情形:当函数递归调用其自身时,调用栈会因帧数过多而溢出,导致执行环境报错。
function foo() {
foo();
}
foo();
任务队列与宏微任务区分
任务队列 Task Queue
任务队列属于Web API的一部分,并非ECMAScript标准的内容,而是由运行环境自行实现。任务队列是一个先进先出(FIFO)的队列,用于排队执行所有回调函数。其基本单位是任务(Task),每个任务都关联一个处理该任务的回调函数。在事件循环(Event Loop)机制中,任务队列内的函数会被压入调用栈执行,并从队列中移除,直到队列为空。
在浏览器的实现中,任务队列被划分为宏任务队列(macrotask queue)和微任务队列(microtask queue)。它们分别负责承载宏任务(macrotask)和微任务(microtask)的排队。其中,宏任务队列与宏任务通常被视为常规的任务队列与任务。
当调用栈内所有同步调用执行完毕后,事件轮询机制会在每次处理完宏任务队列中的一个宏任务后,立即处理微任务队列中的所有微任务。这意味着微任务通常在宏任务处理之前被执行。微任务的执行是连续的,中间不会插入UI渲染或网络事件的处理。
会被添加到宏任务的方法的回调有:
- script:script标签中的代码解析运行
- setTimeout
- setInterval
- setImmediate
- I/O
- UI rendering:UI渲染,每16.6ms放到队列上一次,60fps,如果调用栈被占用则会被阻塞
会被添加到微任务的Web API方法有:
会被添加到微任务的Web API方法有:
- process.nextTick:Node提供的
- Promise
- Object.observe
- MutationObserver
微任务通常仅由开发者编写的代码产生,而宏任务既可能来自开发者代码,也可能源自浏览器本身的事件、渲染或I/O操作。
事件循环执行流程
事件循环 Event Loop
事件循环是JavaScript的事件处理核心机制,它会持续轮询消息队列。当满足调用栈为空且消息队列不为空的条件时,它将把消息队列队头的消息压入执行栈。这种机制确保了函数执行不会被中断,避免了线程切换可能带来的数据不一致等问题。
事件循环在调用栈为空时轮询,顺序为
1.找到任务队列(宏任务队列)的最早被添加的任务并将其添加到调用栈执行
2.执行所有微任务队列内的任务
- 当微任务队列不为空时找到微任务队列最早被添加的任务并将其添加到调用栈执行
3.渲染所有变化 4.如果宏任务队列为空等待宏任务出现 5.返回步骤1
JavaScript运行环境构成
JavaScript运行时 Runtime

浏览器中JavaScript代码的执行,包括调用栈和堆(用于存储变量对象等)的管理,由JavaScript引擎提供。目前广泛使用的是谷歌的V8引擎,Chrome、Edge浏览器以及Node.js均基于该引擎。
事件循环Event Loop、任务队列Task Queue(回调队列Callback Queue)、WebAPI或Node API由运行环境提供。
以上就是详解JavaScript执行模型的详细内容,更多关于JavaScript执行模型的资料请关注本站其它相关文章!