• 线程和进程、浏览器中的JavaScript线程、JavaScript的宏任务和微任务


    认识进程和线程

    线程和进程是操作系统中的两个概念:

    • 进程(process):计算机已经运行的程序,是操作系统管理程序的一种方式;
    • 线程(thread):操作系统能够运行运算调度的最小单位,通常情况下它被包含在进程中;

    听起来很抽象,这里还是给出我的解释:

    • 进程:我们可以认为,启动一个应用程序,就会默认启动一个进程(也可能是多个进程)
    • 线程:每一个进程中,都会启动至少一个线程用来执行程序中的代码,这个线程被称之为主线程
    • 所以我们也可以说进程是线程的容器

    再用一个形象的例子解释:

    • 操作系统类似于一个大工厂;
    • 工厂中里有很多车间,这个车间就是进程;
    • 每个车间可能有一个以上的工人在工厂,这个工人就是线程;

    这里有一幅图, 可以看一下帮助大家理解:

    在这里插入图片描述

    操作系统的工作方式

    操作系统是如何做到同时让多个进程(边听歌、边写代码、边查阅资料)同时工作呢?

    • 这是因为CPU的运算速度非常快,它可以快速的在多个进程之间迅速的切换
    • 当我们进程中的线程获取到时间片时,就可以快速执行我们编写的代码
    • 对于用户来说是感受不到这种快速的切换的

    你可以在Mac的活动监视器或者Windows的资源管理器中查看到很多进程:
    在这里插入图片描述

    浏览器中的JS线程

    我们经常会说JavaScript是单线被程(可以开启workers**)的,但是JavaScript的线程应该有自己的容器进程**:浏览器或者Node。

    浏览器是一个进程吗,它里面只有一个线程吗?

    • 目前多数的浏览器其实都是多进程的,当我们打开一个tab页面时就会开启一个新的进程,这是为了防止一个页面卡死而造成所有页面无法响应,整个浏览器需要强制退出;
    • 每个进程中又有很多的线程,其中包括执行JavaScript代码的线程

    JavaScript的代码执行是在一个单独的线程中执行的:

    • 这就意味着JavaScript的代码,在同一个时刻只能做一件事
    • 如果这件事是非常耗时的,就意味着当前的线程就会被阻塞

    所以真正耗时的操作,实际上并不是由JavaScript线程在执行的:

    • 浏览器的每个进程是多线程的,那么其他线程可以来完成这个耗时的操作
    • 比如网络请求、定时器,我们只需要在特性的时候执行应该有的回调即可;

    浏览器的事件循环

    如果在执行JavaScript代码的过程中,有异步操作呢?

    • 中间我们插入了一个setTimeout的函数调用;
    • 这个函数被放到入调用栈中在线程中的执行会立即结束,并不会阻塞后续代码的执行
    function sum(num1, num2) {
      return num1 + num2
    }
    
    function bar() {
      return sum(20, 30)
    }
    
    setTimeout(() => {
      console.log("10秒后的setTimeout")
    }, 10000)
    
    const result = bar()
    console.log(result)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    微任务宏任务

    但是事件循环中并非只维护着一个队列,事实上是有两个队列:

    • 宏任务队列(macrotask queue):ajax、setTimeout、setInterval、DOM监听、UI Rendering等
    • 微任务队列(microtask queue):Promise的then回调、 Mutation Observer API、queueMicrotask()等

    那么事件循环对于两个队列的优先级是怎么样的呢?

    1. main script中的代码优先执行(编写的顶层script代码);

    2. 执行任何一个宏任务之前(不是队列,是一个宏任务),都会先查看微任务队列中是否有任务需要执行

      • 也就是宏任务执行之前,必须保证微任务队列是空的

      • 如果不为空,那么就优先执行微任务队列中的任务(回调);

    微任务队列中是否有任务需要执行**

    • 也就是宏任务执行之前,必须保证微任务队列是空的

    • 如果不为空,那么就优先执行微任务队列中的任务(回调);

    讲完这些后面我们就可以看看Promise的面试题了

  • 相关阅读:
    vue3 prop验证类型
    【机器学习】KNN算法-模型选择与调优
    传统 51 与STC-Y5内核 51 单片机对比&汇编指令
    DDD之模块(Module)
    元宇宙将给你的行业带来怎样的冲击?
    Linux 下进程管理 API 之创建、查询、退出和收回详解
    机器学习-集成学习(模型融合)方法概述
    论文阅读 Self-Mimic Learning for Small-scale Pedestrian Detection
    IP代理是什么?有什么好处?
    Linux命令使用案例
  • 原文地址:https://blog.csdn.net/m0_71485750/article/details/125503206