浏览器组成和各引擎工作原理
栏目: JavaScript · 发布时间: 5年前
内容简介:这里面最核心的就是渲染引擎和JS引擎,后面会详细介绍这两个引擎的相关内容。常见浏览器的渲染引擎和JS引擎如下:
1.浏览器的主要构成部分
- 1.用户界面
- 2.浏览器引擎(负责窗口管理、Tab进程管理等)
- 3.渲染引擎(有叫内核,负责HTML解析、页面渲染)
- 4.JS引擎(JS解释器,如Chrome和Nodejs采用的V8)
这里面最核心的就是渲染引擎和JS引擎,后面会详细介绍这两个引擎的相关内容。
常见浏览器的渲染引擎和JS引擎如下:
浏览器 | 渲染引擎 | JS 引擎 |
---|---|---|
IE | Trident | Chakra |
Edge | EdgeHTML | Chakra |
Firefox | Gecko | SpiderMonkey |
Chrome | Webkit -> Blink | V8(著名的) |
Safri | Webkit | Javascriptcore |
Opera | Presto->Blink | Carakan |
注:新版本的Chrome采用的渲染引擎是Blink,Blink是由谷歌团队从Webkit衍生开发出来的引擎,主要有应用到Chrome和Opera浏览器。
2.从进程和线程的角度来理解浏览器工作
1)进程和线程
- 进程是cpu资源分配的最小单位(是能拥有资源和独立运行的最小单位)
- 线程是cpu调度的最小单位(线程是建立在进程的基础上的一个程序运行单位,一个进程中可以有多个线程)
进程可以类比为工厂,线程就是工厂里面的工人,一个工厂可以包含一个或者多个工人,工人之间可以相互协作,并且共享工作空间
2)浏览器的多进程架构
现代的浏览器采用的都是多进程架构,主要包含以下三种进程:
1.Browser进程
浏览器的主线程,主要负责浏览器的页面管理、书签、前进后退、资源下载管理等,整个浏览器应用程序只有一个,对应上述浏览器组成中的浏览器引擎。
2.渲染进程
内核进程、负责页面渲染、JS执行,对应的是上述的渲染引擎和JS引擎,一个浏览器可以包含多个渲染进程,每个Tab窗口页对应一个渲染进程
3.GPU进程
负责GPU渲染,整个浏览器应用程序只有一个
4.插件进程
浏览器安装的插件(扩展程序),每个插件会创建一个进程
当打开上面两个Tab时,Chrome任务管理器截图:主要包括
- 1个浏览器进程
- 1个GPU进程
- 1个网络进程
- 2个渲染进程(对应一个Tab一个进程)
- 4个扩展程序进程
MAC的活动监视器中的chorme进程,可以看到所有的渲染、扩展、GPU、网络进程都统一显示为Google Chrome Helper。
这种多进程浏览器架构主要有如下优势:
- 1.避免单个页面奔溃影响整个浏览器
- 2.避免第三方插件奔溃影响整个浏览器
- 3.充分利用多核优势
3)浏览器的渲染进程
- 浏览器有多个渲染进程、一个Tab页面一个(相同的Tab页面可能会被合并)
- 一个渲染进程包含多个线程
一个渲染进程主要包括如下线程:
1.GUI线程(主要负责解析HTML、CSS和渲染页面)
2.JS引擎线程(负责解析和执行JS代码)
3.事件线程(控制事件循环)
4.定时器线程(处理定时器相关逻辑)
5.异步请求线程(发起Ajax时会生成该线程)
线程规则:
1.GUI渲染线程与JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起,页面的更新操作会 等到JS引擎空闲时 执行,涉及任务和微任务相关知识
2.一个渲染进程同时只有一个JS解析线程在运行
3.JS引擎线程不停的处理事件线程推送到事件队列中的任务
4.定时器和异步请求最终生成的回调事件也有事件线程来控制和管理
了解了浏览器的渲染进程之后我们再来看看JS引擎。
4)从事件循环的角度来理解JS引擎的工作过程
在理解什么是事件循环之前,我们先来了解下同步和异步的概念
1.同步和异步
同步是代码执行后就可以获得想要的结果,异步是指代码执行之后不能立即获得结果,
你打电话问书店老板有没有《Javascript权威指南》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。
而异步机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来返回结果。
2.同步任务和异步任务
同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而是由事件线程调度,在满足执行条件的时候放到事件队列中,等待主线程(JS线程)的执行。
3.为什么要有事件循环的概念
JS包含有异步操作(如:Ajax、定时器),这些异步操作完成之后需要通知JS引擎来处理异步操作的返回,如Ajax的Callback。这些异步操作什么时候完成是不确定的,所以需要有一个事件队列,事件线程将已经完成的异步操作的回调任务加载到事件队列中,JS引擎在执行完当前的同步任务之后循环从事件队列中取事件执行。
异步任务:setTImeout、setInterval、Promise、process.nextTick(Node.js)、Ajax
同步任务:除以上异步任务
同步任务和异步任务的执行流程如下:
异步任务统一有事件线程管理,当异步任务完成的时候会被放入到事件队列中,JS在顺序执行完当前的代码之后会从事件队列中读取任务,再重复整个流程,判断该任务是同步还是异步。
4.异步任务的优先级
如果按照上述的简化理解,所有异步任务都按照满足执行条件的顺序放到事件队列中,世界很和平,先来先到,但是在ES6当中,引入了microtask的概念,microtask会在当前的任务执行完成之后立即执行。因为我们将异步任务分为task和microtask,我们又称为宏任务和微任务。
task:setTImeout、setInterval、ajax
microtask:MutationObserve、promise、process.nextTick(Node.js)
这样子加了优先级的话JS的执行又会变得再复杂一点,如下图所示,异步任务执行完成之后会判断他是task还是microtask,再分别加到不同的时间队列中,JS当前任务执行完成之后优先清空当前的microtask队列,而且在每次执行完宏任务的时候都会去清空微任务。
示例:
运行如下示例,就可以验证上述执行流程
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div class="outer"> <div class="inner"></div> </div> <script> // Let's get hold of those elements var outer = document.querySelector('.outer'); var inner = document.querySelector('.inner'); // Let's listen for attribute changes on the // outer element new MutationObserver(function() { console.log('mutate'); }).observe(outer, { attributes: true }); // Here's a click listener… function onClick() { console.log('click'); setTimeout(function() { console.log('timeout'); }, 0); Promise.resolve().then(function() { console.log('promise'); }); outer.setAttribute('data-random', Math.random()); } // …which we'll attach to both elements inner.addEventListener('click', onClick); outer.addEventListener('click', onClick); </script> </body> </html>
5.UI渲染线程什么时候工作
UI渲染线程会在当前的Task执行完成之后,下一个Task执行之前执行,微任务会优先于UI渲染线程,这就意味着我们使用微任务更新的DOM能更快的被渲染出来。另外Vue.js最新版本数据变更的时候采用的是promise和MutationObserver创建微任务: https://github.com/vuejs/vue/...
Demo:用于理解任务和UI渲染之间的关系
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Vue nextTick</title> </head> <body> <!-- jsFiddle例子:http://jsfiddle.net/gkmzns9u/14/ --> <div id="task"> <div id="msg"> {{msg}} </div> <div @click="greet"> click me! </div> </div> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <script type="text/javascript"> const vm = new Vue({ el: '#task', data: { msg: 'hello' }, methods: { greet: () => { // 修改model,触发set方法,调用update方法,添加DOM更新微任务 vm.msg = 'hello world'; vm.msg = 'hello world2'; // 查看DOM,由于是异步更新DOM,根据EventLoop原理可知,这里DOM还没有更新, // hello alert(document.getElementById('msg').innerHTML); // nextTick使用promise,是个微任务,在当前greet方法执行完成之后会立即执行 vm.$nextTick().then(() => { // 由于DOM更新微任务先被添加,先入先出,这里获取的DOM已经是更新好的 // hello world alert(document.getElementById('msg').innerHTML); // 直接修改DOM,同步任务 document.getElementById('msg').innerHTML = 'test' // 立即生效 // test alert(document.getElementById('msg').innerHTML); /* 根据HTML Standard,一轮事件循环执行结束(包括微任务)之后,下轮事件循环执行之前开始进行UI render。即:macro-task任务执行完毕,接着执行完所有的micro-task任务后,此时本轮循环结束,开始执行UI render。UI render完毕之后接着下一轮循环。 */ }); // 由于setTimeout为宏任务,虽然延迟时间为0,但还是要晚于nextTick执行 // 而且可以明显看到在setTimeout回调执行之前页面上已经渲染上test,说明UI Render已经在setTimeout回调之前执行 setTimeout(()=>{ alert('setTimeout start') document.getElementById('msg').innerHTML = 'setTimeout' }, 0) } } }); </script> </body> </html>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Chinese Authoritarianism in the Information Age
Routledge / 2018-2-13 / GBP 115.00
This book examines information and public opinion control by the authoritarian state in response to popular access to information and upgraded political communication channels among the citizens in co......一起来看看 《Chinese Authoritarianism in the Information Age》 这本书的介绍吧!