浏览器运行机制和渲染机制

461 阅读5分钟

JS的运行机制

加载资源的形式

  1. 输入url或者调整页面加载HTML
  2. 加载静态资源
    • 静态资源的压缩合并(减少体积,减少网络请求)
    <script src='one.js'></script>
    <script src='two.js'></script>
    <script src='three.js'></script>
    <script src='one-tow-thress.js'></script>
    
    • 静态资源缓存:通过链接名来控制缓存,内容改变,再改变链接名
    通过版本号来控制资源的请求链接达到清除缓存的作用。
    
    • 使用cdn让资源加载更快
    • 使用SSR(Server Side Render)数据直接输入到HTML中:Vue、React

加载资源的过程

  1. 浏览器根据DNS服务器得到域名对应的IP地址
  2. 像这个IP地址发送http请求
  3. 服务器收到、处理并返回http请求
  4. 浏览器得到返回的内容

浏览器渲染的过程(机制)

  1. 根据HTML结构生成DOMTree
  2. 根据CSS生成CSSOM
  3. 将DOM和CSSOM整合生成RenderTree
  4. 根据RenderTree开始渲染和展示

什么是doctype,它的作用是什么

  • DTD:描述文档类型的,浏览器根据DTD来决定怎么解析文档的内容

什么是doctype是来声明DTD的

doctype的意义是什么

  1. 让浏览器以标准模渲染
  2. 让浏览器知道元素的合法性

常用的doctype有哪些

  1. HTML中有两种doctype有两个版本一个是严格模式,一个是传统模式
  2. HTML5的doctype:<!DOCTYPE html>

回流(重排)

我的理解是当页面中的元素的位置和大小发生直接或者间接发生变化时候会导致回流

触发重排的操作

  1. 增加 修改 删除DOM节点
  2. 移动DOM位置:动画
  3. 修改CSS的样式
  4. Resize窗口,或者滚动
  5. 修改字体

重绘

当页面中元素样式的改变不影响元素在文档中的位置和大小的时候,比如color、background-color、visibility。

回流与重绘

  1. 页面的首次渲染肯定会触发回流和重绘
  2. 回流比重绘的代价高

如果避免回流和重绘带来的性能问题

CSS方面

  1. 避免使用table布局:table布局形成RenderTree通常需要多次计算,通常需要花3倍于同等元素的时间。
  2. 避免多层内联样式。
  3. 将动画效果应用到positon属性为absolute或者fixed的元素上。
  4. 避免使用css表达式如calc()。

JS方面

  1. 避免频繁操作样式,最好将样式定义在一个class中,在DOM末端一次性更改。
  2. 避免频繁操作DOM,最好创建一个documentFragment,在他上面进行一些DOM操作,最好添加到文档中。
  3. 先设置元素的display为none,进行一系列DOM操作,最后在显示出来。

渲染过程的优化

  1. CSS放在前面,JS放在后面
  2. 懒加载(图片懒加载、下拉加载更多)
  <img id='myImg' src='someImg.png' data-img='real.png'/>
  <script type='text/javascript'>
  var img1 = document.getElementById('myImg')
  img1.src = img1.getAttribute('data-img')
  </script>
  1. 减少DOM查询:对查询的DOM用变了存储起来
for(var i = 0; i<document.getElementByTagName('div').length;i++){
    
}
//用一个变量把查询的DOM储存起来
var divList = document.getElementsByTagName('p')
for(var i=0;i<divList.length;i++){
    
}
  1. 减少DOM操作:多个DOM操作合并在一起处理
var frag = document.createDocumentFragment()
for(var i =0;i<10;i++){
    li = document.createElement('li')
    li.innerHTML = '我是插入的片段之一'
    farg.appendChild(li)
}
var insertDom = document.getElementById('insert')
insertDom.appendChild(frag)
  1. 事件节流

每隔一段时间触发一次

var ajax = function(arg){
	//用setTimeout模拟异步请求的接口
	setTimeout(function(){
		console.log(arg)
	},2000)
}

var debounce = function(func,delay,content){
	return function(args){
	  var self =  content||this
	  var _args = arguments
	  clearTimeout(func.id)
	  func.id = setTimeout(function(){
	    func.apply(self,_args)
	  },delay)
	}
}
var  debounceAjax =  debounce(ajax,500)

var btn = document.getElementById('debounce')

btn.addEventListener('keyup',function(e){
	debounceAjax(e.target.value)
})
  1. 函数防抖

用户输入结束或者暂停的时候,才会触发change事件

var throttle = function(func,delay,content){
  return function(args){
	var last 
	var self = content || this
	var _args = arguments
	var now = Date.now()

	if(last && now<last+delay){
		clearTimeout(func.id)
		func.id = setTimeout(function(){
			last = now
			func.apply(self,_args)
		},delay)
	}else{
	    clearTimeout(func.id)
		last = now
		func.apply(self,_args)
	}
}
}

var throttleAjax = throttle(ajax,500)
var btn = document.getElementById('throttle')

btn.addEventListener('keyup',function(e){
	throttleAjax(e.target.value)
})
  1. 尽早执行操作:在DOMContentLoaded的时候执行,而不是等到load之后

为什么把css放在head中?

为了提高性能,在进行DOM渲染的时候就可以直接渲染

为什么把js放在body下面?

  1. 为了不阻塞DOM的渲染
  2. 为了拿到所有的DOM结构

从输入URL到得到HTML的详细过程

  1. 跳转 Redirect
  2. 缓存 Cache
  3. 域名解析 DNS
  4. 创建TCP链接 : 三次握手,如果是HTTPS请求还会创建HTTPS链接
  5. 发送请求 Request
  6. 返回响应 Responsev
  7. 根据HTML生产DOM Tree
  8. 根据CSS生成CSSOM
  9. 将DOM Tree 和CSSOM整合形成Render Tree 10.根据Render Tree渲染页面

为了减少白屏时间,有哪些措施

提高资源的加载速度

减小资源的体积:对代码进行压缩

减少HTTP请求的数量:

  • 将多个CSS文件合并
  • 将多个JS文件合并

合理的使用缓存

  • 缓存的类型
  1. 强缓存:不问浏览器,直接使用本地的
 Expires:服务器的绝对时间 
 Cache-Control:浏览器的相对时间  
 //如果这两个头都设置了,那么以后者为准
  1. 协商缓存:问服务器,资源是否过期,没过期用本地缓存的
Last-Modified:服务器下发的时间  If-Modified-Since:浏览器请求携带服务器下发的时间(Last-Modified)
Etag:服务器下发的标记   If-None-Match:浏览器请求携带服务器下发的(Etag)

非核心代码异步加载

异步加载的方式有哪些

  1. 动态加载脚本:动态创建<script>
  2. defer:defer是在HTML解析完之后才会执行,如果是多个,安照加载的顺序依次执行
  3. async:是在加载完之后立即执行,如果是多个,执行顺序是不确定的,哪个先回来哪个先执行

异步加载的区别

  1. defer:defer是在HTML解析完之后才会执行,如果是多个,安照加载的顺序依次执行
  2. async:是在加载完之后立即执行,如果是多个,执行顺序是不确定的,哪个先回来哪个先执行

DNS预解析

//在页面中增加这句话就是打卡DNS预约解析
<link rel='dns-prefetch' href='//host_name_to_prefetch.com'>
//对于a标签,a标签在http协议中是可以默认进行DNS预解析的,但是https协议下,很多浏览器是默认关闭A标签的DNS预解析的
//强制打开a标签的dns预解析
<meta http-equiv='x-dns-prefetch-control' content='on'>

使用CDN资源

让网络快速到达服务端把资源下载下来,尤其是网页第一次打开的时候,浏览器的缓存起不到作用

onload和DOMContentLoaded的区别

图片和视频等资源是异步加载的

window.addEventListener('load',function(){
    //页面全部资源加载完毕才会执行,包括图片,视频等
})
window.addEventListener('DOMContentLoaded',function(){
    //DOM渲染完即可执行,此时图片、视频等资源可能还没有加载完毕
})
  • jquery和zipto都是应用的DOMContentLoaded判断页面的加载完毕

常见的浏览器内核有哪些

  1. Webkit内核:Chrome Safari
  2. Gecko内核: 火狐
  3. Trident: IE

对HTML语义化的理解

  1. 方便开发人员阅读与维护
  2. 利于浏览器的解析
  3. 利于搜索引擎确定上下文和关键词的权重,利于SEO

cookies,sessionStorage 和 localStorage 的区别

实现div居中显示

水平居中:给div设置一个宽度,通过margin:0 auto实现。

width:200px;
margin:0 auto;

通过绝对定位实现居中

不定宽高的情况下,用transform实现居中

利用flex布局实现居中

display属性有哪些值

用css实现一个三角形

清楚浮动的方式

有一个高度自适应的div,里面有两个div,一个高度100px,希望另一个填满剩下的高度。

display:inline-block 什么时候会显示间隙?

移除空格、使用margin负值、使用font-size:0、letter-spacing、word-spacing

如果需要手动写动画,你认为最小时间间隔是多久,为什么?

多数显示器默认频率是60Hz,即1秒刷新60次,所以理论上最小间隔为1/60*1000ms = 16.7ms

如何修改chrome记住密码后自动填充表单的黄色背景 ?

  input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill {
    background-color: rgb(250, 255, 189); /* #FAFFBD; */
    background-image: none;
    color: rgb(0, 0, 0);
  }