宏任务和微任务,以及事件循环

84 阅读4分钟

01 进程与线程

我们首先来了解一下什么是进程和线程的概念

进程

  • 当一个程序开始运行时,他就是进程,进程包括(程序和程序所用到的内存和系统资源),而一个进程由一个或多个线程组成
  • 总结来说:进程就是正在执行的程序。

线程

  • 线程是程序的一个执行流,每个线程都有自己的专有寄存器(栈指针,程序计算器等),但代码是共享的, 既染不同的线程可以执行同样的函数。
  • 总结来说:是程序执行的一条路径, 一个进程中可以包含多条线程。
  • 通俗理解:例如你打开微信就是打开一个进程,在微信里面和好友视频聊天就是开启了一条线程。

总结

操作系统的设计,因此可以归结为三点:

(1)以多进程形式,允许多个任务同时运行;

(2)以多线程形式,允许单个任务分成不同的部分运行;

(3)提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程之间和线程之间共享资源。

02 了解完线程与进程的概念之后,我们在来看js什么要设计成单线程的

是因为js是运行在浏览器的脚本语音,经常涉及操作dom,如果是多线程,也就意味着同时刻能够执行多个任务,现在试想一个场景,一个线程修改dom,另一个线程删除dom,那么浏览器不知道执行哪个了,所以js要按照一个任务一个任务来执行。

03 同步任务和异步任务

因为js又是单线程,只能一个一个任务来执行,当我们遇到定时器,网络请求等这写需要延时执行的任务,js只能等他们执行完成才能继续执行下面的任务,如果现在网络不好,定时器时间较长,后面任务就一直等待着他们执行完,所以就会造成页面瘫痪的问题 所以js就把这些任务分为同步任务和异步任务,分开执行,互不影响。

  • 同步任务:同步任务不需要进行等待可立即看到执行结果,比如console
  • 异步任务:异步任务需要等待一定的时候才能看到结果,比如setTimeout、网络请求

04 事件循环(Event Loop)

事件循环的比较简单,它是一个在 "JavaScript 引擎等待任务","执行任务"和"进入休眠状态等待更多任务"这几个状态之间转换的无限循环。

引擎的一般算法:

  1. 当有任务时:

    • 从最先进入的任务开始执行。
  2. 没有其他任务,休眠直到出现任务,然后转到第 1 步。

image.png

05 任务队列

事件循环是通过任务队列的机制来进行协调的。一个 Event Loop 中,可以有一个或者多个任务队列(task queue) ,任务队列又分为宏任务微任务,同步任务

宏任务: 主线程代码, setTimeout 等属于宏任务, 上一个宏任务执行完, 才会考虑执行下一个宏任务

微任务: promise .then .catch的需要执行的内容, 属于微任务, 满足条件的微任务, 会被添加到当前宏任务的最后去执行

5.1 宏任务(包含)

1111.png

5.2 微任务(包含)

1:Promise.then  
2:await
3:process.nextTick(Node.js 环境)

任务队列的运行流程

  • 1:进入到script标签,相当于进入了第一次事件循环

  • 2:找到同步任务

  • 3:找到宏任务,把宏任务放到宏任务队列里面

  • 4:找到微任务,把微任务放到微任务队列里面

  • 5:执行同步任务,然后依次去执行微任务队列里面的微任务

  • 6:dom渲染(表示第一次事件循环结束)

  • 1:然后再去执行宏任务,找到了一个宏任务表示进入到了第二次事件循环

  • 2:在按照上面依次反复,直到清空任务队列。

案例

111111.png

<script>
    console.log(1);
    async function fnOne() {
      console.log(2);
      await fnTwo(); // 右结合先执行右侧的代码, 然后等待
      console.log(3);
    }
    async function fnTwo() {
      console.log(4);
    }
    fnOne();
    setTimeout(() => {
      console.log(5);
    }, 2000);
    let p = new Promise((resolve, reject) => { // new Promise()里的函数体会马上执行所有代码
      console.log(6);
      resolve();
      console.log(7);
    })
    setTimeout(() => {
      console.log(8)
    }, 0)
    p.then(() => {
      console.log(9);
    })
    console.log(10);
  </script>
 <script>
    console.log(11);
    setTimeout(() => {
      console.log(12);
      let p = new Promise((resolve) => {
        resolve(13);
      })
      p.then(res => {
        console.log(res);
      })
      console.log(15);
    }, 0)
    console.log(14);
  </script>