js的运行机制

在这之前我们得先清楚一些概念性的问题,什么是进程  什么是线程  什么是单线程 什么是多线程

进程

类比当我们打游戏的时候突然卡死了,我们做的事一般事等待一下然后等待的不耐烦了就会去打开任务管理去,去结束卡死的这个进程,然后电脑就恢复正常了,当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。
而一个进程又是由多个线程所组成的,比如浏览器同时开启多个网页窗口 比如手机同时运行多个app

线程

线程是进程中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数。

JS为什么是单线程

如果 Javascript 是多线程的话,在多线程的交互下,处于 UI 中的 DOM 节点就可能成为一个临界资源,

假设存在两个线程同时操作一个 DOM,一个负责修改一个负责删除,那么这个时候就需要浏览器来裁决如何生效哪个线程的执行结果。

当然我们可以通过锁概念来来解决上面的问题。但为了避免因为引入了锁而带来更大的复杂性,Javascript 在最初就选择了单线程执行。

JS运行机制

js运作在浏览器中,是单线程的,js代码始终在一个线程上执行,此线程被称为js引擎线程, javascript引擎是基于事件驱动单线程执行的,JS引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JS线程在运行JS程序。每一段JS程序都可以看做是一个任务。

因为js引擎是单线程的,单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。如果排队是因为计算量大,CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输入输出设备)很慢(比如Ajax操作从网络读取数据),不得不等着结果出来,再往下执行。

JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,等后面的同步任务执行完毕之后,再回过头执行异步任务队列中结果返回的事件函数

于是,所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在JS引擎上排队执行的任务。异步任务指的是,不进入JS引擎、而进入"任务队列"(task queue)的任务。

宏任务队列setTimeout、setInterval、 setImmediate(Node)、requestAnimation(浏览器)、IO、UI rendering

微任务队列Promise.then、Object.observe、MutationObserver

Event Loop(事件循环)

Event Loop主要包含三大块 :一个函数执行站、一个宏任务队列和一个微任务队列。

在JS引擎上的任务,只有前一个任务执行完毕,才能执行后一个任务,当JS引擎中的任务执行完成了,就会去查询异步的任务队列中是否有可以执行的任务,一旦这些异步任务可以执行了,就会将它添加到JS引擎中,以此循环。由于JS引擎从“任务队列”中读取事件的这个过程是不断循环的,所以整个的这种运行机制又称为 Event Loop(事件循环)。

在执行栈上的任务,只有前一个任务执行完毕,才能执行后一个任务,当执行栈上的任务执行完毕之后,检查微任务队列,取出队列中所有事件压入执行栈执行,完毕之后,检查宏任务队列,取出一个事件压入执行栈执行,完毕之后,再次检查微任务队列,取出所有的事件压入执行栈执行,完毕之后,检查宏任务队列,取出一个事件压入执行栈执行,重复该过程。这整个过程是不断循环执行,所以这种运行机制又称未Event Loop(事件循环)。

注意:对于宏任务每次只从宏任务队列种取一个事件压入执行栈执行,微任务每次从微任务队列种取出所有的事件压入执行栈执行。

 

任务队列数据来源

GUI事件触发线程:JavaScript引擎脚本的执行不影响html元素事件的触发,点击、放大、拖拽浏览器或DOM元素,触发线程捕捉对应的回调函数,添加到任务队列末尾。

定时触发线程::当定时时刻达到的时候,定时线程会把对应的函数添加到任务队列末尾。

HTTP异步请求线程:请求线程执行完毕之后 ,会把对应的函数(success、error)添加任务队列末尾。



posted @ 2020-09-27 20:31  laowang666888  阅读(140)  评论(0编辑  收藏  举报