JavaScript 中线程、事件循环、消息队列、宏任务、微任务

1、JS 线程:

进程:

一个进程就是一个程序,比如我们用浏览器打开1个网页,就是开启了1个进程,打开3个网页就是开启了3个进程。

线程:

一个进程的运行,需要很多个线程的相互配合,比如我们打开QQ这个进程,可能同时有接收消息线程、传输文件线程、检测安全线程等等等,所以一个网页能够正常运行并和用户实现交互,也需要多个进程相互配合。

浏览器有很多线程:

  1. GUI 渲染线程

  2. JS 引擎线程

  3. 定时器触发线程 (setTimeout)

  4. 浏览器事件线程 (onclick)

  5. http 异步线程

  6. EventLoop轮询处理线程

    ...

我们都知道JS是单线程的,即JS的代码只能在一个线程上运行,也就说,JS同时只能执行一个js任务,原因就是 JS的主要用途是与用户互动和操作DOM。设想一段JS代码,分发到两个并行互不相关的线程上运行,一个线程在DOM上添加内容,另一个线程在删除DOM,那么会发生什么?以哪个为准?所以为了避免复杂性,JS从一开始就是单线程的。

JS 引擎图:

2、事件循环:

事件循环英文名叫 Event Loop,其中事件循环可以拆分为 “事件” + “循环”。

事件包括很多,像我们常见的点击事件(click)、鼠标事件(Mouseover)等交互事件;事件冒泡、事件委托等;addEventListener、removeEventListener()等。当然,有了事件,肯定要有事件处理器,当事件发生时,在事件处理器中做一些事件操作。

但是当这些事件发生时,浏览器是怎么知道发生了这些事件?

用伪代码来表示,如果没有事件循环,那我们的线程只是静态的,当代码执行完一次之后,代码就失效了,那对于 I/O 事件是没有办法捕获的,但是如果我们有了事件循环,将进程的渲染变为激活状态,然后我们再事件监听器中做出响应。

//如果没有事件循环,函数执行后该段代码就失效了
function mainThread() {
     console.log("Hello World!");
}
mainThread();

//---------------------

//有事件循环时
function clickTrigger() {
    return "我点击按钮了"
}
function mainThread(){
    while(true){
        if(clickTrigger()) { 
            console.log(“通知click事件监听器”) 
        }
        clickTrigger = null;
     }
}
mainThread();

//在事件处理器中对事件进行处理
button.addEventListener('click', ()=>{
    console.log("多亏了事件循环,我(浏览器)才能知道用户做了什么操作");
})

3、消息队列:

消息队列也叫任务队列,是一个静态的队列存储结构,存储异步成功后的后调函数字符串,先成功的回调函数排在队列前面。需要注意的是,异步函数成功后,才把回调函数放进队列中,而不是一开始就把所有的异步函数直接放进队列里面。如我们设置一个定时器,3秒后执行一个函数,那这个函数一定是在3秒后才放入队列中。

代码:

1 var a = 2;
2 setTimeout(fun A)
3 ajax(fun B)
4 console.log()
5 dom.onclick(func C)

在这段代码中,主线程运行到第二行 setTimeout(fun A) 时,会把这行代码交给定时器触发线程去执行;运行到第三行 ajax(fun B) 时,会把这行代码交给 http 异步线程去执行;运行到第五行 dom.onclick(func C) 时,会把这行代码交给浏览器事件循环去执行。然后这些异步代码的回调函数会被各自的执行线程保存着,在将来的某个时候,把这些回调函数交给 EventLoop 轮询处理线程去执行。

4、宏任务与微任务:

宏任务:

  • setTimeout,setInterval,setImmediate,requestAnimationFrame
  • UI交互事件
  • 网络请求等等

微任务:

  • Promise.then (Promise执行本身时是属于同步代码,只有.then才是微任务)
  • process.nextTick(Node.js 环境)

时间循环,消息队列与宏任务、微任务之间的联系:

  • 宏任务加入消息队列;
  • 每个宏任务队列里面有微任务队列,执行宏任务的过程中遇到微任务,就把微任务加入到微任务队列中;
  • 宏任务微任务的队列都为空时才会执行下一个宏任务;
  • 事件循环捕获队列出队的宏任务和微任务执行。

事件循环会不断地处理消息队列出队的任务,而宏任务指的就是入队到消息队列中的任务,每个宏任务都有一个微任务队列,宏任务在执行过程中,如果此时产生微任务,那么会将产生的微任务入队到当前的微任务队列中,在当前宏任务的主要任务完成后,会依次出队并执行微任务队列中的任务,直到当前微任务队列为空才会进行下一个宏任务。

执行顺序:

执行同步代码 ==> 检查微任务并执行 ==> 执行宏任务1 ==> 检查微任务并执行 ==> 执行宏任务2 ==> 检查微任务并执行 ==> 执行宏任务3 ......

总的结论就是,执行宏任务,然后执行该宏任务产生的微任务,若微任务在执行过程中产生了新的微任务,则继续执行微任务,微任务执行完毕后,再回到宏任务中进行下一轮循环。

这类知识掘金上有好多文章可供学习,我这里也是在学习中做的简要总结。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值