欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

js执行机制

程序员文章站 2022-05-03 12:07:43
js是单线程的,为什么可以执行异步操作呢? 这归结与浏览器(js的宿主环境)通过某种方式使得js具备了异步的属性。 区分进程和线程: 进程:正在运行中的应用程序。每个进程都自己独立的内存空间。例如:打开的浏览器就是一个进程。 线程:进程的子集,是独立的。线程在共享的内存空间中运行。 浏览器是多进程的 ......

js是单线程的,为什么可以执行异步操作呢?

这归结与浏览器(js的宿主环境)通过某种方式使得js具备了异步的属性。

 

 

区分进程和线程:

 

进程:正在运行中的应用程序。每个进程都自己独立的内存空间。例如:打开的浏览器就是一个进程。

线程:进程的子集,是独立的。线程在共享的内存空间中运行。

 

 

浏览器是多进程的。如下图:

js执行机制

 

 

 并且每打开一个页面就创建了一个独立的进程。进程内有自己的多线程。如果浏览器是单进程的,那么某个页面崩了,就会影响整个浏览器。

 

浏览器有哪些进程:

1.browser(浏览器):浏览器的主进程(负责协调,主控)只有一个,作用有:
  • 负责浏览器界面显示,与用户交互。如前进,后退等
  • 负责各个页面的管理,创建和销毁其他进程
  • 将renderer(渲染器)进程得到的内存中的bitmap,绘制到用户界面上
  • 网络资源的管理,下载等
2.第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建
3.gpu进程:最多一个,用于3d绘制等
4.浏览器渲染进程(浏览器内核)(renderer(渲染器),内部是多线程的)默认每个tab页面一个进程,互不影响。主要作用 :页面渲染,脚本执行,事件处理等
 
浏览器渲染进程(浏览器内核)包含的线程:
1. gui渲染线程
• 负责渲染浏览器界面,解析html,css,构建dom树和renderobject树,布局和绘制等。
• 当界面需要重绘(repaint)或由于某种操作引发回流(reflow)时,该线程就会执行
• 注意,gui渲染线程与js引擎线程是互斥的,当js引擎执行时gui线程会被挂起(相当于被冻结了),gui更新会被保存在一个队列中等到js引擎空闲时立即被执行。
2. js引擎线程(
“javascript 引擎”通常被称作一种 虚拟机。也称为js内核,负责处理javascript脚本程序。(例如v8引擎)
• js引擎线程负责解析javascript脚本,运行代码。
• js引擎一直等待着任务队列中任务的到来,然后加以处理,一个tab页(renderer进程)中无论什么时候都只有一个js线程在运行js程序
• 同样注意,gui渲染线程与js引擎线程是互斥的,所以如果js执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞。
3. 事件触发线程
• 归属于浏览器而不是js引擎,用来控制事件循环(可以理解,js引擎自己都忙不过来,需要浏览器另开线程协助)
• 当js引擎执行代码块如settimeout时(也可来自浏览器内核的其他线程,如鼠标点击、ajax异步请求等),会将对应任务添加到事件线程中
• 当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待js引擎的处理
• 注意,由于js的单线程关系,所以这些待处理队列中的事件都得排队等待js引擎处理(当js引擎空闲时才会去执行)
4. 定时触发器线程
• 传说中的setinterval与settimeout所在线程
• 浏览器定时计数器并不是由javascript引擎计数的,(因为javascript引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确)
• 因此通过单独线程来计时并触发定时(计时完毕后,添加到事件队列中,等待js引擎空闲后执行)
• 注意,w3c在html标准中规定,规定要求settimeout中低于4ms的时间间隔算为4ms。
5. 异步http请求线程
• 在xmlhttprequest在连接后是通过浏览器新开一个线程请求
• 将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调再放入事件队列中。再由javascript引擎执行。

 

gui渲染线程与js引擎线程互斥:
由于javascript是可操纵dom的,如果在修改这些元素属性同时渲染界面(即js线程和ui线程同时运行),那么渲染线程前后获得的元素数据就可能不一致了。因此为了防止渲染出现不可预期的结果,浏览器设置gui渲染线程与js引擎为互斥的关系,当js引擎执行时gui线程会被挂起,gui更新则会被保存在一个队列中等到js引擎线程空闲时立即被执行。
 
 
js执行机制:js是单线程的,每当执行函数就把函数推入栈中,但有异步的操作就让浏览器的线程(webapi)去处理,处理完放到任务队列里,当主线程(执行栈)执行完毕时,如果任务队列里有任务,就执行。
 
js执行机制

 

 这也就是为什么下面代码会先输出b,然后是a的原因。settimeout的函数会放到任务队列中,而console.log('b')是主线程。

     settimeout(() => {
            console.log('a');
        }, 0);
        console.log('b');