进程和线程
了解进程和线程,更好的理解js单线程。
官方术语
进程是cpu资源(包括内存等)分配的最小单元(是能拥有资源和独立运行的最小单元)。
线程是cpu调度的最小单元。
cpu资源包括什么??
这里的调度的意思是什么??
网络上看到很多次的比喻:
将进程比作一个工厂,工厂和工厂直接互不影响。工厂里面有很多工人,工人相当于线程,工厂里面的电力等资源工人都可以使用,一个或多个工人合作完成任务。
从上面可以得出:
- 进程之间互不影响
- 一个进程包含一个或多个线程
- 同一个进程中的线程共享资源
浏览器的进程和线程
首先浏览器是多进程的,可以打开谷歌浏览器的任务管理器查看。基本上一个标签页就是一个进程,一个插件也是一个进程,但是多个空白标签页合并为一个进程,浏览器做了优化。多进程的好处是什么呢?当一个标签页或者插件崩溃了,并不会影响到其他的进程,如果是单进程的话,只要有一个崩溃的话会影响整个浏览器。多进程充分利用多核优势。
多进程为什么可以充分利用多核优势??
浏览器包含的进程
Browser进程:浏览器的主进程,只要一个,负责主控和协调。主要的作用跟整个浏览器相关的:
- 浏览器的界面与用户的交互
- 负责各个页面的管理,创建和销毁其他进程
- 网络资源的管理和下载
- 负责将Renderer进程内存里的Bitmap绘制成界面 o(╥﹏╥)o不懂啥意思
第三方插件进程:这个比较容易理解,一个插件一个进程,仅当插件启用时才会被创建。
GPU进程:最多一个,用于3D绘制。
什么是GPU??
Renderer进程:浏览器渲染进程,默认每个Tab页面一个进程,互不影响。 Renderer进程是多线程的,主要作用为页面渲染、脚本执行、事件处理等。
Renderer进程包含的线程
Renderer进程是前端关注的重点,主要包括GUI渲染线程、JS引擎线程、事件触发线程、定时器触发线程、ajax网络请求线程等。
GUI渲染线程主要负责:
- HTML、CSS解析,构建DOM树和RenderObject树,布局和绘制
- 当发生Repaint或者reflow时,该线程就是执行
- GUI渲染线程和JS引擎线程是互斥的,这两个线程同时只有一个线程运行
JS引擎线程主要作用:
- 负责执行javascript脚本
- 等待任务队列的任务触发,一个Renderer进程只有一个JS线程在运行JS程序。
- JS引擎线程和GUI渲染线程是互斥的
事件触发线程主要作用:
- 用来控制事件循环
- 当JS引擎执行
setTimeout
、发送Ajax,绑定事件响应等,会将对应的任务添加到该线程 - 当对应的事件符合触发条件时,该线程会把事件添加到任务队列的末尾,等待JS引擎空闲时执行。
定时器触发线程:
- setTimeout 和setInterval所在线程
- 因为JS是单线程的,如果处于阻塞线程状态,会影响计时的准确性,所以另开线程。
- 计时完毕后,会将事件添加到任务队列的末尾,等待JS引擎空闲时执行。
ajax网络请求线程:
- 在XMLHttpRequest请求连接成功后,浏览器新开一个线程请求
- 在状态请求状态变更时,会产生状态变更事件,将回调函数放在任务队列的末尾,等待JS引擎空闲时执行。
js为什么是单线程
其实这与它的用途有关。作为浏览器脚本语言,JavaScript 的主要用途是与用户互动,以及操作 DOM。若以多线程的方式操作这些 DOM,则可能出现操作的冲突。假设有两个线程同时操作一个 DOM 元素,线程 1 要求浏览器删除 DOM,而线程 2 却要求修改 DOM 样式,这时浏览器就无法决定采用哪个线程的操作。当然,我们可以为浏览器引入“锁”的机制来解决这些冲突,但这会大大提高复杂性,所以 JavaScript
从诞生开始就选择了单线程执行。
setTimeout 只是将事件插入到task queue
,必须等到execution context stack
(执行栈) 执行完成,
主线程才会去执行指定的回调函数。所以当程序耗时很长时,并不能保证setTimeout能够在指定时间执行。比如:
1 | setTimeout(()=>{ |
并不能保证在0 ms 之后打印 start并且setTimeout
最短间隔不得低于 4ms,低于这个值会自动增加。setTimeout(fn,0)
的意思是让fn
在主线程最早有空闲的时候执行。
在vue
中,数据的改变并不会马上触发Dom
元素的更新,需要使用$nextTick
或者setTimeout(fn,0)
,保证可以获取到更新后的DOM
元素
nodejs中的event-loop
1 | console.log(1); |