您的位置:首页 > Web前端 > JavaScript

JS引擎运行机制笔记总结

2018-03-20 19:45 387 查看

前言

       之前一直以为JS代码的执行是一行一行的读取、执行并输出结果,才发现原来并不是那样的。看了一些大佬的文章,以下是关于该知识点的总结及一些个人的理解,参考链接统一放置在文末,若发现有错误,希望大神们能指点指点我这个前端小菜鸟。


线程与进程

进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体。
线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元。

区别:
进程是操作系统分配资源的最小单位,线程是程序执行的最小单位
• 一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线;
• 进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段、数据集、堆等)及一些进程级的资源(如打开文件和信号)。
• 调度和切换:线程上下文切换比进程上下文切换要快得多。
最常看到的一个关于线程与进程的比喻是,进程就像是工厂的车间,线程像是车间里一个一个的工人。

多进程与多线程:
多进程指的是在同一个时间里,同一个计算机系统中如果允许两个或两个以上的进程处于运行状态。
多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。


浏览器包含的进程

浏览器是多进程的,主要包含以下进程
1. Browser进程:浏览器的主进程(负责协调、主控),只有一个
○ 负责浏览器界面显示,与用户交互。如前进,后退等
○ 负责各个页面的管理,创建和销毁其他进程
○ 将Renderer进程得到的内存中的Bitmap,绘制到用户界面上
○ 网络资源的管理,下载等
2. NPAPI插件进程和Pepper插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建,只会被创建一次,可被共享
3. GPU进程:最多只有一个,并且仅当GPU硬件加速打开的时候才会被创建,主要用于对3D图形加速调用的实现; 
4. 浏览器渲染进程(浏览器内核)(Renderer进程是多线程的):默认每个Tab页面一个进程,互不影响。
          主要作用为页面渲染,脚本执行,事件处理等          blink/webkit的渲染工作主要是在这个进程完成,可能有多个,具体个数允许用户配置;
 5.其它类型的进程:包括linux下的Zygote进程,render进程就是有它创建;Sandbox进程,用于安全进制中;
有以下特征:
Browser进程和页面的渲染是分开的,保证了页面的渲染导致的崩溃不会导致浏览器主界面的崩溃;
每个网页是独立的进程,保证了页面之间相互不影响;
插件进程也是独立的,插件本身的问题不会影响游览器主界面和网页;
GPU硬件加速进程也是独立的。

在浏览器中打开一个网页相当于新起了一个进程(进程内有自己的多线程),浏览器有时会将多个进程合并



                                        ( Chrome的任务管理器 )


Browser进程和浏览器内核(Renderer进程)的通信过程

Browser进程收到用户请求
4000
,首先需要获取页面内容(譬如通过网络下载资源),随后将该任务通过RendererHost接口传递给Render进程
Renderer进程的Renderer接口收到消息,简单解释后,交给渲染线程,然后开始渲染渲染线程接收请求,加载网页并渲染网页,这其中可能需要Browser进程获取资源和需要GPU进程来帮助渲染
当然可能会有JS线程操作DOM(这样可能会造成回流并重绘)
最后Render进程将结果传递给Browser进程

Browser进程接收到结果并将结果绘制出来



浏览器内核

浏览器内核是多线程,在内核控制下各线程相互配合以保持同步,一个浏览器通常由以下常驻线程组成:GUI 渲染线程、JavaScript引擎线程、定时触发器线程、事件触发线程、异步http请求线程

GUI渲染线程
负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等;
当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程执行;
Chrome/Safari/Opera用的是Webkit引擎,IE用的是Trident引擎,FireFox用的是Gecko引擎。
Javascript引擎线程(单线程)
也称为JS内核,负责处理Javascript脚本程序(例如V8引擎);
负责解析Javascript脚本,运行代码;
如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞。
(当浏览器在执行JavaScript程序的时候,GUI渲染线程会被保存在一个队列中,直到JS程序执行完成,才会接着执行。)
事件触发线程
当事件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理;
这些事件可以是当前执行的代码块如定时任务、也可来自浏览器内核的其他线程如鼠标点击、AJAX异步请求等(JS是单线程,这些事件得等待JS引擎处理)。
定时触发器线程
W3C在HTML标准中规定,规定要求setTimeout中低于4ms的时间间隔算为4ms;
浏览器定时计数器并不是由JavaScript引擎计数的,(JavaScript引擎是单线程, 如果处于阻塞线程状态就会影响记计时的准确)
异步http请求线程
在XMLHttpRequest连接后通过浏览器新开的一个线程请求;

将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件放到 事件队列中等待执行
GUI渲染线程与JavaScript引擎为互斥的关系,当JS引擎执行时GUI线程会被“冻结”,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行;



事件循环

       JS引擎线程运行的时候,产生堆(heap)和栈(stack),栈中的代码调用各种外部API,我理解的是使用其他线程来执行任务,执行完毕后,它们在"任务队列"中加入各种事件(click,load,done)。
       如setTimeout(function(){//函数代码},1000),将调用定时触发器线程来计时,1秒后,回调函数将被推到任务队列。因此定时器的回调函数并不是计时达到设置的时间就立即执行,实际的执行时间不一定准确。
       只要栈中的代码执行完毕,主线程(JS引擎线程)就会去读取"任务队列",依次执行那些事件所对应的回调函数,这个反复的过程就是事件循环。



任务划分(一)

把任务分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)
同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

任务队列类型:microtask queue(微任务队列),macrotask queue(宏任务队列)。
microtask queue:唯一,整个事件循环当中,仅存在一个;执行为同步,同一个事件循环中的microtask会按队列顺序,串行执行完毕;

macrotask queue:不唯一,存在一定的优先级(用户I/O部分优先级更高);异步执行,同一事件循环中,只执行一个。



JS执行机制
       判断JS是同步还是异步,同步任务进入主进程执行,异步任务调用外部api执行,当满足触发条件后,被推入任务队列,直到主线程空闲时,才会去队列中查看是否有可执行的异步任务,如果有就推入主进程中执行。

栗子:



执行结果:



任务划分(更准确):
macro-task(宏任务):包括整体代码script,setTimeout,setInterval ,setImmediate,I/O,各种事件的回调函数(,UI rendering)
micro-task(微任务):Promise,process.nextTick(在node环境下,process.nextTick的优先级高于Promise)

JS执行机制:
       执行整体代码这个宏任务,执行的过程发现宏任务或微任务,将其放入对应的任务队列。当整体代码这个宏任务执行完之后,查看是否有可执行的微任务,有则执行,没有则执行下一个宏任务。



栗子2:



执行结果:



参考链接: http://www.imweb.io/topic/58e3bfa845e5c13468f567d5 http://www.ruanyifeng.com/blog/2014/10/event-loop.html https://www.cnblogs.com/hity-tt/p/6733062.html https://juejin.im/post/5a6ad46ef265da3e513352c8 https://juejin.im/post/5a6547d0f265da3e283a1df7 http://blog.csdn.net/Steward2011/article/details/51319298
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: