JavaScript 单线程机制与执行顺序详解

作者:青柠

时间:2026-10-22

浏览:106

本文解析 JavaScript 的单线程特性,通过 setTimeout 示例说明异步任务在事件循环中的执行逻辑。同时梳理函数作用域、全局与局部变量的访问规则,以及预编译与执行两个阶段的差异,帮助开发者掌握代码执行的先后顺序。

文章目录

JavaScript 单线程模型解析

一、JavaScript语言具备单线程特性

从严格定义来看,JavaScript缺乏多线程机制,所有任务均按顺序在单线程中执行。

1、单线程的概念解析

简而言之,后续代码的执行必须等待当前代码执行完毕后方可进行。以下通过具体代码示例加以说明。

异步任务与事件循环机制


 for(var i=1;i<=3;i++){
   setTimeout(function(){
     console.log(i); //输出:4,4,4
   },0)
 }

观察上述代码,尽管定时器时间设定为0,预期循环执行一次即打印一个i值,但最终输出结果均为4,4,4。此现象源于JavaScript的单线程运行机制。

执行流程中,首先遇到for循环并进入线程。当i等于1时,代码执行至setTimeout,此时for循环尚未结束,该定时器任务被放入线程池等待。随后for循环继续执行,当i等于2时,新的setTimeout同样被放入线程池等待……以此类推,直至for循环完成3次迭代。此时主线程空闲,线程池中等待的setTimeout任务依次执行并打印i值。由于for循环结束后i的值已变为4,因此最终打印出三个4。

2、针对上述现象的改进代码方案

解决异步打印问题的方案


//将var变为let
for(let i=1; i<=3; i++){
  setTimeOut(function(){
    console.log(i); //输出的结果为1,2,3
  },0);
}
//用自执行函数进行包裹
for(var i=1; i<=3; i++){
  !function(i){
    setTimeOut(function(){
      console.log(i); //输出的结果为1,2,3
    },0);
  }(i)
}

函数作用域与变量访问规则

二、JavaScript函数作用域与代码执行机制

>>> 函数作用域详解

首先需明确以下核心概念:

1、JavaScript语言中不存在类似C语言的块级作用域。

2、JavaScript的顶层作用域为window对象范围,即全局作用域,在此声明的变量称为全局变量。

3、函数内部声明的变量仅能在该函数内访问,外部无法使用,此类变量称为局部变量。

4、JavaScript支持函数嵌套,多层函数嵌套形成了作用域的层级结构,这被称为作用域链。

5、JavaScript作用域链的变量访问规则如下:

(1)、若当前作用域内存在目标变量,则直接使用该作用域内的变量。

(2)、若当前作用域内不存在目标变量,则向上一层作用域查找,直至全局作用域。

代码执行阶段与预编译机制

>>> 代码执行顺序分析

JavaScript代码的执行过程包含两个主要阶段:

1、代码检查装载阶段(预编译阶段),此阶段负责变量和函数的声明,但不进行赋值操作,变量默认值为undefined。

2、代码执行阶段,此阶段对变量进行赋值及函数调用。

基于上述概念,通过以下代码示例进行具体说明:

变量提升与执行顺序实例


var a=1; //声明了一个全局变量
function func(){
  console.log(a); //输出:undefined。打印a,而在func这个作用域中已经声明了a变量,按照js的执行顺序,此时的a并未被赋值。
  var a=1;
  console.log(a); //输出:1。
}
func();

分析上述代码:第一个a输出undefined。原因在于js作用域链访问规则,当前作用域内存在变量a,故使用当前作用域变量。结合js代码执行顺序,此时a仅声明未赋值,默认值为undefined,因此输出undefined。

而第二个a输出1,是因为此时a已完成声明并赋值,故a输出1。

总结

以上内容介绍了JavaScript代码执行的先后顺序问题,希望能对大家有所帮助。如有任何疑问,欢迎留言,小编将及时回复!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章