请简单介绍一下浏览器的渲染过程
-
浏览器内核:渲染引擎(Firefox 中叫做 Gecko\Chrome 和 Safari 中都是基于 WebKit 开发)、JS引擎
-
浏览器工作大体流程:
- 构建DOM树:浏览器接收到一段HTML,识别Token,构建节点并生成DOM(字节数据=>字符串=>Token=>Node=>DOM)
- 构建CSSDOM树:浏览器接收到一段CSS,识别Token,构建节点并生成CSSDOM(字节数据=>字符串=>Token=>Node=>CSSDOM)
- 构建渲染树:当生成 DOM 树和 CSSOM 树以后,就需要将这两棵树组合为渲染树,只会包括需要显示的节点和这些节点的样式信息
- 布局(回流):浏览器要弄清楚各个节点在页面中的确切位置和大小
- 重绘:绘制,合成图层,显示在屏幕上
- 渲染过程中遇到JS文件怎么处理
- JS的加载、解析与执行会阻塞DOM的构建
- JS文件也会导致CSSDOM阻塞DOM的构建
- 真了解回流和重绘吗?
- 当网页生成的时候,至少会渲染一次。在用户访问的过程中,还会不断重新渲染
- 回流必定会发生重绘,重绘不一定会引发回流
- 重绘只是影响元素的外观、风格,而不会影响布局
- 回流是因为元素的规模尺寸、布局、隐藏等改变而需要重新构建
- 常见引起回流属性和方法
- 添加或者删除可见的DOM元素
- 元素尺寸改变——边距、填充、边框、宽度和高度
- 内容变化,比如用户在input框中输入文字
- 浏览器窗口尺寸改变——resize事件发生时
- 计算 offsetWidth 和 offsetHeight 属性
- 设置 style 属性的值:width\height\margin\padding\display等
-
常见引起重绘属性和方法
color\background\border-style\visibility -
如何减少回流、重绘
- 使用 transform 替代 top
- 使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流(改变了布局)
- 不要把节点的属性值放在一个循环里当成循环里的变量
for(let i = 0; i < 1000; i++) {
// 获取 offsetTop 会导致回流,因为需要去获取正确的值
console.log(document.querySelector('.test').style.offsetTop)
}
- 不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局
- CSS 选择符从右往左匹配查找,避免节点层级过多
- async和defer的作用是什么?有什么区别?
- async 属性表示异步执行引入的 JavaScript,与 defer 的区别在于,如果已经加载好,就会开始执行
- defer 属性表示延迟执行引入的 JavaScript,即这段 JavaScript 加载时 HTML 并未停止解析,这两个过程是并行的
- 加载多个JS文件,async
- 为什么操作 DOM 慢
- 相当于不同线程之间的通信
- 可能带来重绘回流
- 渲染页面时常见哪些不良现象?
- 白屏问题:有些浏览器渲染机制(比如chrome)要先构建DOM树和CSSOM树,构建完成后再进行渲染,如果CSS部分放在HTML尾部,由于CSS未加载完成,浏览器迟迟未渲染,从而导致白屏;也可能是把js文件放在头部,脚本会阻塞后面内容的呈现,脚本会阻塞其后组件的下载,出现白屏问题
- 无样式内容闪烁(FOUC):由于浏览器渲染机制(比如firefox),再CSS加载之前,先呈现了HTML,就会导致展示出无样式内容,然后样式突然呈现的现象
/*
给定一个只包括 '(',')','{','}','[',']'的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
输入: "()"
输出: true
示例2:
输入: "()[]{}"
输出: true
示例3:
输入: "(]"
输出: false
示例4:
输入: "([)]"
输出: false
示例5:
输入: "{[]}"
输出: true*/
/**
*@param{string}s
*@return{boolean}
*/
var isValid = function(str){
var flag = true;
if(str === "" || str === " "){
return flag;
}
var tmpStr = str.trim(),
arr = [],
left = ['(','[','{'],
right = [')',']','}'];
for(var i = 0; i < tmpStr.length; i++){
if(left.indexOf(tmpStr[i]) > -1){
arr.push(tmpStr[i]);
}else{
if(arr.pop() !== left[right.indexOf(tmpStr[i])]){
flag = false;
}
}
}
if(arr.length !== 0){
flag = false;
}
return flag;
}