目录
浏览器渲染大致流程
- 处理 HTML 标记并构造 DOM 树。
- 处理 CSS 标记并构造 CSSOM 树。
- 将 DOM 与 CSSOM 合并成一个渲染树。
- 根据渲染树来布局,以计算每个节点的几何信息。
- 将各个节点绘制到屏幕上。
构建渲染树
- 从 DOM 树的根节点开始遍历每个 可见 节点。
- 对于每个可见的节点,找到 CSSOM 树中对应的规则,并应用它们。
- 根据每个可见节点以及其对应的样式,组合生成渲染树。
第一步遍历节点的时候,需要知道什么节点是不可见的。
- 一些不会渲染输出的节点。比如 script、meta、link等。
- 某些节点通过 CSS 隐藏。注意 visibility: hidden 与 display: none 是不一样的。前者隐藏元素,但元素仍占据着布局空间(即将其渲染成一个空框),而后者 (display: none) 将元素从渲染树中完全移除,元素既不可见,也不是布局的组成部分。
注意: 渲染树只包含可见的节点
回流(reflow)
当 渲染树 中部分或全部, 因元素的尺寸、布局、隐藏等改变而需要重新构建,浏览器重新渲染的过程称为 回流。
会导致回流的操作:
- 页面首次渲染。
- 浏览器窗口大小发生改变。
- 元素尺寸或者位置发生改变。
- 元素内容变化(文字数量或者图片大小发生改变)。
- 元素字体大小的改变。
- 添加或者删除可见的
DOM
元素。 - 激活
CSS
伪类 (eg::hover
)。 - 查询某些属性或调用某些方法。
常用的会导致回流的属性和方法。
clientWidth
、clientHeight
、clientTop
、clientLeft
offsetWidth
、offsetHeight
、offsetTop
、offsetLeft
scrollWidth
、scrollHeight
、scrollTop
、scrollLeft
scrollIntoView()
、scrollIntoViewIfNeeded()
getComputedStyle()
getBoundingClientRect()
scrollTo()
重绘(repaint)
当页面中元素样式的改变并不影响布局时(eg:color
、background-color
等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。
一句话: 回流必将引起重绘,重绘不一定会引起回流。
性能影响
有时即使仅仅回流一个单一的元素,它的父元素以及任何跟随它的元素也会产生回流。
现代浏览器会对频繁的回流或重绘操作进行优化:
浏览器会维护一个队列,把所有引起回流和重绘的操作放入队列中,如果队列中的任务数量或者时间间隔达到一个阈值的,浏览器就会将队列清空,进行一次批处理,这样可以把多次回流和重绘变成一次。
当你访问以下属性或方法时,浏览器会立刻清空队列:
clientWidth
、clientHeight
、clientTop
、clientLeft
offsetWidth
、offsetHeight
、offsetTop
、offsetLeft
scrollWidth
、scrollHeight
、scrollTop
、scrollLeft
scrollIntoView()
、scrollIntoViewIfNeeded()
getComputedStyle()
getBoundingClientRect()
scrollTo()
因为队列中可能会有影响到这些属性或方法返回值的操作,即使你希望获取的信息与队列中操作引发的改变无关,浏览器也会强行清空队列,确保你拿到的值是最精确的。
优化重绘回流
- 减少对 render tree 的操作 ,合并多次多DOM和样式的修改
- 减少对一些style信息的请求,尽量利用好浏览器的优化策略
- 直接改变className. (把要修改的样式集中到一个 class 内统一修改);
- 避免使用
table
布局 (尽量不要使用表格布局,如果没有定宽表格一列的宽度由最宽的一列决定,那么很可能在最后一行的宽度超出之前的列宽,引起整体回流造成table可能需要多次计算才能确定好其在渲染树中节点的属性,通常要花3倍于同等元素的时间。) - 尽可能在DOM树的最末端改变class,尽可能在DOM树的里面改变class(可以限制回流的范围)
- 将需要多次重排的元素,position属性设为absolute或fixed,这样此元素就脱离了文档流,它的变化不会影响到其他元素。例如有动画效果的元素就最好设置为绝对定位;
- 使用display:none技术,只引发两次回流和重绘;
OSI七层模型
OSI七层模型 ,全称为开放系统互联参考模型,是国际标准化组织(ISO) 和 国际电报电话咨询委员会(CCITT)联合制定的开放系统互联参考模型,为开放式互联信息系统提供了一种功能结构的框架。
计算机网络七层模型
应用层(数据)
表示层(数据)
会话层(数据)
传输层(数据报文)
网络层 (数据分组)
数据链路层 (帧)
物理层 (比特)
TCP/IP四层模型
应用层 :应用进程 ->文件传输协议(FTP)、域名服务(DNS)、超文本传输协
议(HTTP)
传输层:TCP /UDP
网络层:ICMP/IGMP/ARP/RARP/IP 网络协议 IP
网络接口层:网络接口
每一层的协议如下:
物理层:RJ45、CLOCK、IEEE802.3 (中继器,集线器,网关)
数据链路:PPP、FR、HDLC、VLAN、MAC (网桥,交换机)
网络层:IP、ICMP、ARP、RARP、OSPF、IPX、RIP、IGRP、 (路由器)
传输层:TCP、UDP、SPX会话层:NFS、SQL、NETBIOS、RPC
表示层: JPEG、MPEG、ASII
应用层: FTP、DNS、Telnet、SMTP、HTTP、WWW、NFS
每一层的作用如下:
物理层:通过媒介传输比特,确定机械及电气规范(比特 Bit)
数据链路层:将比特组装成帧和的传递(帧 Frame)
网络层:负责数据包从源到宿的传递和网际互连(包 PackeT)
传输层:提供端到端的可靠报文传递和错误恢复(段 Segment)
会话层:建立、管理和终止会话(会话协议数据单元 SPDU)
表示层:对数据进行翻译、加密和压缩(表示协议数据单元 PPDU)
应用层:允许访问 OSI 环境的手段(应用协议数据单元 APDU)
var,let,const的区别
1 var的特点
- 在函数外使用,作用域是全局的;在函数内使用,作用域是局部的
- 存在变量提升
- 一个变量可多次声明,后面的声明会覆盖前面的
2 let 的特点
- 作用域是块级作用域 {}
- 不存在变量声明,let声明某变量前,该变量不能用,称为暂时性死区
- 不允许在相同作用域中重复声明,不同作用域中重复声明不会报错
3 const 的特点
- let的特点都具有
- const声明只读变量,声明后值不能再次改变
- const必须给变量一个初始化值
- const并不是变量的值不能改动,而是变量指向的内存地址所保存的数据不得改动
瀑布流
瀑布流又称瀑布流式布局,是比较流行的一种网站页面布局方式。视觉表现为参差不齐的多栏布局,即多行等宽元素排列,后面的元素依次添加到其后,等宽不等高,根据图片原比例缩放直至宽度达到我们的要求,依次按照规则放入指定位置。
get和post的区别
1、url可见性:
get,参数url可见;
post,url参数不可见
2、数据传输上:
get,通过拼接url进行传递参数;
post,通过body体传输参数
3、缓存性:
get请求是可以缓存的
post请求不可以缓存
4、后退页面的反应
get请求页面后退时,不产生影响
post请求页面后退时,会重新提交请求
5、传输数据的大小
get一般传输数据大小不超过2k-4k(根据浏览器不同,限制不一样,但相差不大)
post请求传输数据的大小根据php.ini 配置文件设定,也可以无限大。
6、安全性
这个也是最不好分析的,原则上post肯定要比get安全,毕竟传输参数时url不可见,但也挡不住部分人闲的没事在那抓包玩。安全性个人觉得是没多大区别的,防君子不防小人就是这个道理。对传递的参数进行加密,其实都一样。
7、数据包
GET产生一个TCP数据包;POST产生两个TCP数据包。对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。
两栏布局的实现方式
- 侧边栏左浮动+正文部分overflow:auto
- 定位实现两栏布局
- 纯浮动形式
- 浮动+常规流
深拷贝和浅拷贝
拷贝,就是赋值。把一个变量赋给另外一个变量,就是把变量的内容进行拷贝。把一个对象的值赋给另外一个对象,就是把一个对象拷贝一份。
深拷贝和浅拷贝主要是针对对象的属性是对象(引用类型)
1.浅拷贝
浅复制仅仅是指向被复制的内存地址,如果原地址中对象被改变了,那么浅复制出来的对象也会相应改变。
- 特点:只要任意一个拷贝对象(或原有对象)中的引用发生改变,所有的对象都会受到影响;
2.深拷贝
在计算机中开辟了一块新的内存地址用于存放复制的对象。
- 特点:修改任意一个对象,不会对其他对象产生影响;
闭包
闭包 是指有权访问另外一个函数作用域中的局部变量的函数。声明在一个函数中的函数,叫做闭包函数。而且内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后
特点
1、让外部访问函数内部变量成为可能
2、局部变量会常驻在内存中
3、可以避免使用全局变量,防止全局变量污染
4、会造成内存泄漏(有一块内存空间被长期占用,而不被释放)
事件流
页面触发一个事件时,会按照一定的顺序来响应事件,事件的响应过程为事件流事件冒泡
-
事件流包括了三个阶段:事件捕获阶段,处于目标阶段,事件冒泡阶段,当点击一个div元素时,以下就是事件流的顺序:
- 顶级对象(window)接收到click事件,然后逐级向下捕获
- 目标元素(div)接收到到事件
- 对事件做出响应,逐级向上冒泡到顶级对象
-
事件冒泡是目标元素接受事件,然后逐级向上传播到顶级元素为止
-
事件捕获与事件冒泡是相反的,是顶级元素先接收到事件,再逐级向下传播到目标元素为止
原型
原型:每个函数都有 prototype 属性,该属性指向原型对象;使用原型对象的好处是所有对象实例共享它所包含的属性和方法。
我们创建的每一个函数都有一个prototype
(原型)属性,这个属性指向的是通过调用构造函数来创建出来的对象实例的原型对象,这个原型对象可以让所有对象实例共享它所包含的属性和方法。
原型链
原型链:主要解决了继承的问题;每个对象都拥有一个原型对象,通过__proto__ 指针指向其原型对象,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层,最终指向 null。
例:假如现在我们有两个构造函数A跟B,我们让构造函数A的原型对象等于构造函数B的实例,根据前面的推论,这个时候A的原型对象就包含指向B的原型对象的指针,再假如又有一个构造函数C,让A的原型对象等于C的实例,上述关系依旧成立,以此类推便形成了实例与原型的链条,即原型链
原型搜索机制
当访问一个实例属性或方法时,在通过原型链实现继承的情况下,首先会在实例中搜索该属性,在没有找到属性或方法时,便会沿着原型链继续往上搜索,直到原型链末端才会停下来。
所有引用类型默认都继承了Object
,而这个继承也是通过原型链实现的,也就是说,所有函数的默认原型都是Object
的实例,这也是所有自定义类型都会继承toString()
、valueOf()
等默认方法的根本原因。
Object.prototype的原型为null。
js缓存方法
cookie
session
区别
①cookie数据保存在客户端,session数据保存在服务器端。
②session 能够存储任意的 java 对象,cookie 只能存储 String 类型的对象
③Session比Cookie更具有安全性(Cookie有安全隐患,通过拦截或本地文件找得到你的cookie后可以进行攻击)
④Session占用服务器性能,Session过多,增加服务器压力
⑤单个Cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个Cookie,Session是没有大小限制和服务器的内存大小有关。
防抖和节流
两者都是优化高频率执行js代码的一种手段。
-
防抖:就是一定时间内,只会执行最后一次任务;
防抖意味着 N 秒内函数只会被执行一次(最后一次),如果 N 秒内再次被触发,则重新计算延迟时间。
-
节流:就是一定时间内,只执行一次 ;
区别: 函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。 (比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。)
DFS(深度优先遍历)
二叉树
1.先序遍历,访问根结点,先序遍历左子树,先序遍历右子树,(上图遍历结果为:0134256)
2.中序遍历,中序遍历左子树,访问根结点,中序遍历右子树,(遍历结果为:3140526)
3.后序遍历,后序遍历左子树,后续遍历右子树,访问根结点,(遍历结果:3415620)
BFS(广度优先遍历)
-
广度优先遍历是先搜索所有兄弟和堂兄弟结点再搜索子孙结点。
-
深度优先遍历则是先搜索一个结点的所有子孙结点,再去搜索这个结点的兄弟结点。
(上图二叉树广度优先遍历结果是:0123456)