JavaScript为什么是单线程-JS异步与回调详解

本文探讨JavaScript为何采用单线程设计,讲解同步任务、异步任务与回调队列的概念,阐述事件循环(Event Loop)的工作原理,包括浏览器和Node.js中的差异,并介绍宏任务与微任务的执行流程,帮助理解JavaScript中的异步处理机制。
摘要由CSDN通过智能技术生成

JavaScript为什么是单线程

JavaScript 最初被设计为浏览器脚本语言,主要用途包括对页面的操作、与浏览器的交互、与用户的交互、页面逻辑处理等。如果将 JavaScript 设计为多线程,那当多个线程同时对同一个 DOM 节点进行操作时,线程间的同步问题会变得很复杂。

同步任务与异步任务

  • 同步任务:在主线程上排队执行的任务,前一个任务完整地执行完成后,后一个任务才会被执行。

  • 异步任务:不会阻塞主线程,在其任务执行完成之后,会再根据一定的规则去执行相关的回调。

同步任务与函数调用栈

在 JavaScript 中,同步任务基本上可以认为是执行 JavaScript 代码。在上一讲内容中,我们提到 JavaScript 在执行过程中每进入一个不同的运行环境时,都会创建一个相应的执行上下文。那么,当我们执行一段 JavaScript 代码时,通常会创建多个执行上下文。

而 JavaScript 解释器会以栈的方式管理这些执行上下文、以及函数之间的调用关系,形成函数调用栈(call stack)(调用栈可理解为一个存储函数调用的栈结构,遵循 FILO(先进后出)的原则)。

我们来看一下 JavaScript 中代码执行的过程:

  1. 首先进入全局环境,全局执行上下文被创建并添加进栈中;

  2. 每调用一个函数,该函数执行上下文会被添加进调用栈,并开始执行;

  3. 如果正在调用栈中执行的 A 函数还调用了 B 函数,那么 B 函数也将会被添加进调用栈;

  4. 一旦 B 函数被调用,便会立即执行;

  5. 当前函数执行完毕后,JavaScript 解释器将其清出调用栈,继续执行当前执行环境下的剩余的代码。

由此可见,JavaScript 代码执行过程中,函数调用栈栈底永远是全局执行上下文,栈顶永远是当前执行上下文

在不考虑全局执行上下文时,我们可以理解为刚开始的时候调用栈是空的,每当有函数被调用,相应的执行上下文都会被添加到调用栈中。执行完函数中相关代码后,该执行上下文又会自动被调用栈移除,最后调用栈又回到了空的状态(同样不考虑全局执行上下文)。

调用栈示例

还是来个示例,捋清楚一下

let a = 10;
function test() {
   
    console.log("你好");
};
test();

通过Chrome的调试工具可以看到,代码执行过程中产生了两个执行上下文,当前栈顶为test函数的执行上下文,顺便一说,这里的Scope中有三个:LocalScriptGlobalLocal代表函数的作用域,而Script则是let关键字产生的块级作用域,Global毋庸置疑就是全局环境

image-20210810091552016

我们也可以直接通过console.trace();API向控制台输出一个输出一个堆栈跟踪

image-20210810092049409

但是栈的容量是有限制的,所以当我们没有合理调用函数的时候,可能会导致爆栈异常,此时控制台便会抛出错误:

递归爆栈

function fn(n) {
   
    if (n < 1) {
   
        return
    }
    console.log(n);
    fn(n - 1)
}

fn(100000)

image-20210810092608156

这样的一个函数调用栈结构,可以理解为 JavaScript 中同步任务的执行环境,同步任务也可以理解为 JavaScript 代码片段的执行。

同步任务的执行会阻塞主线程,也就是说,一个函数执行的时候不会被抢占,只有在它执行完毕之后,才会去执行任何其他的代码。这意味着如果我们一个任务执行的时间过长,浏览器就无法处理与用户的交互,例如点击或滚动

因此,我们还需要用到异步任务。

异步任务与回调队列

异步任务

异步任务包括一些需要等待响应的任务,包括用户交互、HTTP 请求、定时器等。

setTimeout(() => {
   
    console.log("张
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值