js 代码的运行过程

111 阅读3分钟

浏览器渲染进程

js 代码的解析运行是由js 解析引擎完成的,js 引擎运行在一个线程中,这个线程被称之为js 主线程

js 主线程只会执行同步代码,我们编写的异步网络请求等异步任务并不是由js 主线程来执行的,而是由浏览器渲染进程中的其他线程执行的。

这些异步任务代码是由浏览器的渲染进程中的其他线程执行的,js 引擎也是浏览器渲染进程中的一个线程。 浏览器渲染进程中的线程主要包括:

  • JS引擎线程
  • 事件触发线程
  • 定时触发器线程
  • 异步http请求线程
  • GUI渲染线程
    浏览器渲染进程参考此处

js 主线程的执行过程

js代码的执行过程分为解析执行两个阶段。

代码解析阶段

在代码解析阶段,js 会构建执行栈结构,执行栈(ECS)可以理解为一个栈结构,栈中的每一项就是一个 执行环境(context,或者说执行上下文),栈的构建过程存在于js代码的执行的整个过程中,也就是说是边 解析边执行的。js代码的执行过程就是 一个一个的执行上下文的构建,入栈,出栈的过程。

js代码的第一个执行环境就是全局执行环境,又称为执行上下文。在对顶级代码解析完毕后,全局执行环境中已经包含了这个上下文中的代码体,作用域链条,以及this值,和调用的函数信息。这个时候会进入代码执行阶段。

代码执行阶段(同步代码)

在代码执行阶段,会给上下文中的变量赋值并执行上下文中的代码体。

当代码体执行中遇到函数时,会构建函数执行上下文,这个上下文中包含了这个函数的代码体,作用域链条,以及this 值。

在函数上下文构建完成后,就会执行这个函数的代码体,如果代码体中有函数,会重复上个过程,如果没有函数,会在代码体执行完成后,退出当前函数执行上下文,继续执行全局上下文中的代码体。

当全局执行上下文也执行完毕后,整个js 代码就会执行完毕。

执行图解

如下代码执行图解

var name = "哈哈";

function boo() {
  console.log("boo");
}
function bar() {
  console.log("bar");
}

console.log(name);

截屏2023-02-18 14.01.54.png

关于ECS,GEC,FEC 等概念,请看链接

代码执行阶段(异步任务->事件循环)

其次我们再来了解一下异步代码的执行过程。 (1)我们知道js代码的执行是单线程的,但我们编写的代码中是有很多异步代码的,比如promise,async函数,html元素绑定的事件,setTimeout 等等,这些代码是如何在单线程体系中在恰当的时机执行的呢?

当我们的代码中包含了异步代码时,异步代码不会在执行阶段直接执行,而是会被丢到事件队列中,当js的同步代码执行完毕后,js线程会到事件队列中取出异步代码并执行。

(2)事件队列分为宏任务队列和微任务队列

常见宏任务:setTimeout setInterval requrestAnimationFrame,html元素绑定的各种事件

常见微任务:new promise().then(回调) process.nextTick

事件循环相关概念请点击