宏任务与微任务

 javascript是单线程的,可以理解为同一个时间只能做一件事情。 

   原因:。js是作为浏览器的脚本语言,主要是实现用户与浏览器的交互,以及操作dom;这决定了它只能是单线程,否则会带来很复杂的同步问题。 举个例子:如果js被设计了多线程,如果有一个线程要修改一个dom元素,另一个线程要移动这个dom元素,此时浏览器就会一脸茫然,不知所措。所以,为了避免复杂性,保证程序执行的一致性。JavaScript就被设计为单线程。

  线程和进程:

    进程(process)和线程(thread)是操作系统的基本概念,

    进程:CPU进行资源分配的基本单位

    线程:CPU调度的最小单位,是建立在进程的基础上运行的单位,共享进程的内存空间

  进程特征:

  1. 进程依赖于程序运行而存在,进程是动态的,程序是静态的;
  2. 进程是操作系统进行资源分配和调度的一个独立单位(CPU除外,线程是处理器任务调度和执行的基本单位);
  3. 每个进程拥有独立的地址空间,地址空间包括代码区、数据区和堆栈区,进程之间的地址空间是隔离的,互不影响。

   线程特性:

  1. 原子性
  2. 可见行
  3. 有序性

  进程VS线程

  1.区别:进程是操作系统进行资源分配的最小单元,线程是操作系统进行运算调度的最小单元。

  2.从属关系不同:进程中包含了线程,线程属于进程。

  3.开销不同:进程的创建、销毁和切换的开销都远大于线程。

  4.拥有资源不同:每个进程有自己的内存和资源,一个进程中的线程会共享这些内存和资源。

  5.控制和影响能力不同:子进程无法影响父进程,而子线程可以影响父线程,如果主线程发生异  常会影响其所在进程和子线程。

  6.CPU利用率不同:进程的CPU利用率较低,因为上下文切换开销较大,而线程的CPU的利用率较高,上下文的切换速度快。

  7.操纵者不同:进程的操纵者一般是操作系统,线程的操纵者一般是编程人员。

浏览器进程与线程

1.Browser进程:浏览器的主进程(负责协调、主控),只有一个。

    主要作用:

  • 负责浏览器界面显示,与用户交互。如前进,后退等
  • 负责各个页面的管理,创建和销毁其他进程
  • 将渲染(Renderer)进程得到的内存中的Bitmap(位图),绘制到用户界面上
  • 网络资源的管理,下载等

2、第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建
3、GPU进程:最多一个,用于3D绘制等
4、浏览器渲染进程(即通常所说的浏览器内核)(Renderer进程,内部是多线程的):主要作用为页面渲染,脚本执行,事件处理等

5、网络进程:主要负责页面的网络资源加载,之前是作为一个模块运行在浏览器进程里面的,直至最近才独立处理,成为单独一个进程。

   浏览器渲染进程又包含五个线程:

1)GUI渲染线程 

当浏览器收到响应的html后,该线程开始解析HTML文档构建DOM树,解析CSS文件构建CSSOM,合并构成渲染树,并计算布局样式,绘制在页面上(HTML解析规则,CSS解析规则,渲染流程细节)

当界面样式被修改的时候可能会触发reflow和repaint,该线程就会重新计算,重新绘制,是前端开发需要着重优化的点。
注意:GUI渲染线程和JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。

(2)JS引擎线程

JS引擎线程也称为JS内核,负责处理Javascript脚本程序,解析Javascript脚本,运行代码;
JS引擎线程一直等待着任务队列中任务的到来,然后加以处理,一个Tab页中无论什么时候都只有一个JS引擎线程在运行JS程序;
注意:GUI渲染线程与JS引擎线程的互斥关系,所以如果JS执行的时间过长,会造成页面的渲染不连贯,导致页面渲染加载阻塞。

(3)事件触发线程

归属于渲染进程而不是JS引擎,用来控制事件轮询(可以理解,JS引擎自己都忙不过来,需要浏览器另开线程协助)

当JS引擎执行代码块如鼠标点击、AJAX异步请求等,会将对应任务添加到事件触发线程中

当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理任务队列的队尾,等待JS引擎的处理

注意,由于JS的单线程关系,所以这些待处理队列中的事件都得排队等待JS引擎处理(当JS引擎空闲时才会去执行)

(4)定时器触发进程

即setInterval与setTimeout所在线程;

浏览器定时计数器并不是由JS引擎计数的,因为JS引擎是单线程的,如果处于阻塞线程状态就会影响记计时的准确性;

因此使用单独线程来计时并触发定时器,计时完毕后,添加到事件队列中,等待JS引擎空闲后执行,所以定时器中的任务在设定的时间点不一定能够准时执行,定时器只是在指定时间点将任务添加到事件队列中;

注意:W3C在HTML标准中规定,定时器的定时时间不能小于4ms,如果是小于4ms,则默认为4ms。

(5)异步http请求线程

XMLHttpRequest连接后通过浏览器新开一个线程请求;

检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将回调函数放入事件队列中,等待JS引擎空闲后执行;

 

event loop 事件循环

因为js单线程的特点,如果某段程序需要等待一会再执行,后面的程序都会被阻塞,这样也就带来了一些问题。 为了解决这个问题,js把任务分为了两种:同步任务、异步任务两种任务的差异就在于执行的优先级不同event loop就是对任务的执行顺序做了详细的规范。

同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕,后一个任务才会执行;

异步任务:不进入主线程、而进入任务队列的任务,只有当主线程上的所有同步任务执行完毕之后,主线程才会读取任务队列,开始执行异步任务。异步任务又分为宏任务微任务

执行顺序:    同步任务 -> 微任务 -> 宏任务

区别:异步不会阻塞程序的执行,同步会阻塞程序的执行

什么是 event loop

事件循环(event loop)就是 任务在主线程不断进栈出栈的一个循环过程。任务会在将要执行时进入主线程,在执行完毕后会退出主线程。

下面就是这个循环的步骤:

1.把同步任务队列 或者 微任务队列 或者 宏任务队列中的任务放入主线程。

2.同步任务 或者 微任务 或者 宏任务在执行完毕后会全部退出主线程。

在实际场景下大概是这么一个顺序:

1.把同步任务相继加入同步任务队列。

2.把同步任务队列的任务相继加入主线程。

3.待主线程的任务相继执行完毕后,把主线程队列清空。

4.把微任务相继加入微任务队列。

5.把微任务队列的任务相继加入主线程。

6.待主线程的任务相继执行完毕后,把主线程队列清空。

7.把宏任务相继加入宏任务队列。无time的先加入,像网络请求。有time的后加入,像setTimeout(()=>{},time),在他们中time短的先加入。

8.把宏任务队列的任务相继加入主线程。

9.待主线程的任务相继执行完毕后,把主线程队列清空。

宏任务:

setTimeout setInterval Ajax DOM事件  script(整体代码)   I/OUI交互事件   postMessageMessage  Channel setImmediate(Node.js 环境)

微任务:

 Promise async/await  Object.observe MutationObserver    process.nextTick(Node.js 环境)

优先级排行:process.nextTick>promise.then>setTimeout>setImmediate

new Promise中的代码会立即执行,then函数分发到微任务队列,process.nextTick分发到微任务队列Event Queue

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值