如果你对事件循环还是不太了解,快来和我一起学习一下吧~~~
在浏览器中包含了许多的进程。
- 主进程
- GPU进程
- 第三方插件进程
- 渲染进程(浏览器内核)
其中我们最关注的是
渲染进程,主要负责页面的渲染,脚本执行,事件处理等
渲染进程中又包含了许多的线程
- GUI渲染线程
- 负责页面渲染,布局和绘制,当页面需要重排和重绘时,就会执行
- 与js引擎线程互斥,这样可以防止在渲染的时候操作dom导致渲染不可预期
- JS引擎线程
- JS引擎线程是一个单线程的,与GUI渲染进程互斥
- 主要负责解析和执行js脚本
- 事件触发线程(管理事件队列)
- 当事件触发的时候,会将事件放入到js所在执行队列中,比如点击事件等
- 定时器触发线程
- settimeout 和setInterval由该线程计时,计时完毕后,通知事件触发线程
- 异步请求线程
- 用来处理ajax 请求,请求完成后,通知事件触发线程
Js 是单线程的, 因为涉及到dom操作,多线程需要进行同步判断,单线程降低了复杂度
但是因为是单线程,所以当遇到定时器,网络请求的时候就会阻塞线程,所以js 将代码分为了一个个任务,Js 分为同步任务和异步任务,任务在js引擎上执行,当遇到同步任务的时候,先执行,形成一个执行栈,当遇到异步任务的时候,就会根据不同的异步任务让不同的线程执行,当异步任务的触发条件达成后,会将回调事件放到由事件触发线程管理的任务队列中(任务队列有两个,一个宏任务队列,一个微任务队列), 当执行栈中的同步任务执行完成后,若微任务队列中有,则清空微任务,若微任务队列中没有回调,就会从任务队列(宏任务队列)中取出一个异步任务的回调加入到执行栈中开始执行。(异步的回调任务中也可能有同步任务,其他异步任务,就还是会按照上面这个顺序进行)
- js 引擎线程只会执行执行栈中的事件
- 执行栈中的代码执行完毕,就会读取事件队列中的事件
- 事件队列中的回调事件,是由各自线程插入到事件队列中的
- 如此循环
微任务队列是为了让异步任务有优先级的概念,于是又设计了一个高优先级的队列(微任务队列),每次执行完普通宏任务后,就去把所有的高优先级的任务执行一遍,清空微任务队列,然后执行下一个宏任务
JS引擎线程 和负责页面渲染的GUI线程互斥,为了让js任务和dom渲染任务有序进行,每当一个宏任务执行完后,检查微任务队列中有没有,有就执行清空微任务队列,然后就会由GUI线程进行渲染,渲染完成后,然后执行下一个宏任务。
同步任务1和同步任务2执行过程中产生了微任务的执行流程,且第一个宏任务中产生了微任务
同步任务1-->渲染-->同步任务2-->渲染-->微任务-->渲染-->宏任务-->微任务-->渲染-->宏任务-->渲染
同步任务1和同步任务2中没有产生微任务的流程,且第一个宏任务中产生了微任务
同步任务1-->渲染-->同步任务2-->渲染-->宏任务-->微任务-->渲染-->宏任务-->渲染
任务分类
-
同步任务
-
宏任务 定时器回调,ajax 会调, dom事件回调
-
微任务 Promise.then回调 mutationObserver 回调
总结:
代码执行的是,遇到同步任务直接执行,遇到异步任务就会根据任务类型分别放到宏任务队列和微任务队列,同步任务执行完后,查看微任务队列,如果有微任务,则保证把所有的微任务全部执行完(包括执行微任务中产生的新的微任务), 然后去执行查看宏任务队列,执行下一个宏任务,如果在执行宏队列的时候,产生了新的微任务,则执行完微任务再去接着执行宏队列 ,执行完后,查看微任务队列,重复循环,直到宏任务队列为空。
垃圾回收机制
标记清理
当申明一个变量的时候,这个变量会被加上存在于上下文中的标记,当变量离开上下文时候,也会被加上离开上下文的标记
引用计数
申明变量并给他赋值一个引用值,引用数为1,如果其他值又有引用到,则引用数加一