进程是资源分配的最小单位,线程是CPU调度的最小单位
(一)进程一个进程就是一个程序的运行实例,
每启动一个应用程序,操作系统都会为此程序创建一块内存,用来存放代码、数据数据、一个执行任务的主线程,我们把这样的一个运行环境叫进程。
一个进程关闭,操作系统则会回收为该进程分配的内存空间
(二)线程线程是依附于进程的,而进程中使用多线程并行处理能提升运算效率。
进程与线程之间的关系: (进程是火车,线程是每节车厢)
- 进程中的某一线程执行出错,都会导致整个进程的崩溃
- 线程之间共享进程中的公共数据。
- 当一个进程关闭之后,操作系统会回收进程所占用的内存。
- 进程之间的内容相互隔离
- 一个浏览器主进程: 主要负责显示渲染进程生成的页面图层、用户交互、子管理进程,提供存储等功能
- 一个GPU进程 :负责图形处理
- 一个网络进程:负责网络资源的下载
- 多个渲染进程(浏览器的核心部分,一般称为浏览器内核):默认情况下,每个tab页面一个进程,互不影响
-- 特殊情况1:如多个空白tab会合并成一个进程;
-- 特殊情况2:从一个标签页中打开了另一个新标签页,当新标签页和当前标签页属于同一站点的话,那么新标签页会复用当前标签页的渲染进程核心任务是将 HTML、CSS 和 JavaScript 转换为网页图层,通知浏览器主线程进行界面显示;渲染进程都是运行在沙箱模式下渲染进程中包含以下线程:
(1).GUI渲染线程
(2) Javascript引擎线程
(3) 事件触发线程(归属于浏览器而不是JS引擎)
(4)定时触发器线程
(5)异步http请求线程
(6)合成线程
(7)IO线程:处理和其他进程进行通信
GUI渲染线程与JS引擎线程是互斥的,不能一并执行 - 多个插件进程:负责页面中的插件运行;也是运行在沙箱模式下
各进程之间通过 IPC 来通信
二、浏览器渲染流程第一步,解析:主线程开始解析HTML- 浏览器收到HTML,HTML解析器开始解析HTML,生成DOM Tree,并保存在浏览器内存中
-- 同时开启一个预解析线程,用来分析 HTML 文件中包含的Javascript、 CSS 、Img等资源,通知网络进程提前加载这些资源 - 解析遇到CSS(style、行内、link),CSS解析器开始对CSS进行解析,生成CSSOM( 即styleSheets)
- 样式计算:(css样式的继承、层叠等规则)
- 转换样式中的属性值,如color: red; => color: rgb(255, 0, 0)
- 计算出DOM每个节点的具体样式
- 遇到 <script> ,渲染线程停止解析剩余的 HTML 文档,等待Javascript 资源加载,Javascript引擎执行脚本完成后,HTML再继续解析
根据DOM和styleSheets生成LayoutTree布局树(渲染树),所有不可见的元素会被忽略,如head标签 , display:none的元素,script标签等
第三步,布局计算- 渲染引擎计算出布局树中各元素的几何位置,并将计算结果保存在布局树中,
- 布局阶段的输出就是我们常说的盒子模型,它会精确地捕获每个元素在屏幕内的确切位置与大小
渲染引擎根据布局树生成图层树,
第五步, 绘制- 主线程根据图层树生成绘制列表,交给合成线程
- 合成线程对图层进行分割,生成大小固定的图块
- 合成线程按照视口附近的图块来优先交给GPU进程
GPU进程根据不同图块生成位图,还给合成线程
第七步,合成- 合成线程收到各图块位图之后,发出合成命令,交给浏览器主进程
- 浏览器主进程然后进行界面显示
渲染流程中的特殊情况:
1. 重排(回流):指修改了元素几何属性,如位置、尺寸、内容、结构等变化,引发元素几何位置变化,浏览器需要重新计算样式、构建布局树,开始之后的一系列子阶段,这个过程就叫重排。
重排需要更新完整的渲染流水线,所以开销也是最大的。触发重排的情况:(Javascript操作DOM,引发不同渲染流水线重新工作)
- 添加或删除可见的DOM元素
- 元素位置改变
- 元素尺寸改变
- 元素内容改变
- 改变字体大小会引发回流
- 页面渲染器初始化
- 浏览器窗口大小发生改变
- 当获取一些属性时,浏览器为了获得正确的值也会触发回流,这样使得浏览器优化无效,包括
(1) offset(Top/Left/Width/Height)
(2) scroll(Top/Left/Width/Height)
(3) cilent(Top/Left/Width/Height)
(4) width,height
(5) 调用了getComputedStyle()或者IE的currentStyle
指修改了元素的外观样式,不会引起几何位置变化,直接入绘制阶段,生成绘制列表,然后执行之后的一系列子阶段,这个过程就叫重绘。如背景颜色、边框颜色,文字颜色等
重绘省去了布局和分层阶段,所以执行效率会比重排操作要高一些。重排必然带来重绘,但是重绘未必带来重排3. 直接合成:指更改一个既不要布局也不要绘制的属性,直接分割图块阶段,然后交给浏览器主进程并不线上显示,这个过程叫做直接合成。
如 transform:translate(100px, 100px)
相对于重绘和重排,直接合成能大大提升效率
减少重排(回流)、重绘, 方法:
- 多次dom 操作合成一次,批量操作,例如 createDocumentFragment,vue框架虚拟DOM和diff算法
- 使用 class 操作样式,而不是频繁操作 style
- 处理动画时,使用will-change和transform 做优化
在css中使用will-change,渲染引擎会将该元素单独生成一个图层
编译结果为两部分:执行上下文、可执行代码
showName();//函数showName被执行
console.log(myname);//undefined
var myname = '小白'
function showName() {
console.log('我是小白');
}
编译时的执行上下文如下:(变量环境部分)
{
showName: xxx, //showName 函数在堆内存的引用地址
myname: undefined
}
可执行上下文如下:
showName();
console.log(myname);//undefined
myname = '小白'
- 执行上下文:是 JavaScript 执行一段代码时的运行环境
每个执行上下文包含以下几个部分: - 变量环境
- 词法环境
- 外部环境,即当前执行上下文中变量的外部引用,用来指向外部的执行上下文,也称为 outer
- this,this的指向在于当前函数的调用方式
-直接调用指向全局对象window (严格模式下则是undefined)
-通过对象调用,this指向该对象
-通过apply、call、bind等方法调用则指向第一个参数对象
-箭头函数中的this指向外层函数的this(解析箭头函数不会创建执行上下文)
let userInfo = {
userName: "小白",
age: 18,
sayHello: function () {
setTimeout(function () {
console.log(`${this.userName},你好`) //undefined
}, 100)
}
}
userInfo.sayHello()
修改一个函数this指向的方法:
- 缓存外部的this, 如 var _this = this;
- 使用箭头函数
- 使用app、call、bind改变this指向
问题:
- var变量提升
编译时变量声明提升,并初始化值为undefind, - 函数声明提升
- 同时声明了多个相同名字的函数,后声明的会覆盖前面声明的函数
- 函数声明的优先级高于变量提升,变量名和函数声明的名字相同时,采用函数名
解决: 引入let、const、块级作用域
(二)函数执行(调用)过程- 执行上下文栈:
用来管理执行上下文,后进先出
- 全局执行上下文:执行全局代码生成一个全局执行上下文,仅有一个,伴随页面的整个生存周期
- 函数执行上下文:执行每个函数会生成一个函数执行上下文,可以有多个, 当函数执行结束,该函数的执行上下文会被销毁
一段代码解析完成,即执行上下文创建完成,就立即执行可执行代码
var a = 2
function add(b,c){
return b c
}
function addAll(b,c){
var d = 10
result = add(b,c)
return a result d
}
addAll(3,6)
第一步,解析全局代码,创建全局执行上下文,压入调用栈,并全局的执行可执行代码