从输入url到渲染页面的整个过程
基础答案:
从三个方面来说:
1.加载资源的形式。
资源的一般形式有html,媒体文件(图片,视频),js,css等。
2.加载资源的过程。
DNS解析:域名 -> IP地址
浏览器根据IP地址想服务器发起Http请求
服务器处理http请求,并返回给浏览器
3.渲染页面的过程。
根据HTML代码生成DOM Tree
根据CSS代码生成CSSOM
将DOM Tree和CSSOM整合形成Rendeer Tree
根据RenderTree渲染页面
遇到
所以常见的优化中,css的引入放在head里面,这样可以避免dom结构先按默认值渲染,而后加载到css的时候,因cssom和dom tree整合而重复渲染。
将scripe标签放在body最后也是这个道理。以免渲染到一半,遇到js了,完了以后又重新渲染。
我们更期望先渲染完dom结构,再执行js,可以加快视觉上的页面渲染速度。
window.onload跟DOMContentLoaded的区别
window.addEventListener('load',function(){
// 页面的全部资源加载完成后才执行,包括图片,视频
})
document.addEventListener('DOMContentLoaded',function(){
// DOM渲染完即可执行,此时图片视频可能还未加载完成
})
所以用onload来做实际上不是很好的选择。
前端性能优化
这是一个综合性问题,没有标准答案,但要尽量全面,并加入自己的思考。
其中某些问题可能会单独提问:比如手写房防抖和节流。
性能优化原则:
多使用内存、缓存或其他方法,减少cpu计算量,减少网络加载耗时,空间换时间。
从哪里入手解决:
1.让加载更快
减少资源体积:压缩代码。(webpack生产环境打包压缩)
减少访问次数:合并代码,SSR服务端渲染,缓存
使用更快的网络:CDN
2.让渲染更快
CSS放在head,JS放在body最下面
尽早开始执行JS,用DOMContentLoaded触发
懒加载(图片懒加载,上滑加载更多等等)
对DOM查询进行缓存
频繁的DOM操作,合并到一起插入DOM结构
throttle和debounce
比如webpack打包会将所有的js文件整合成一个js文件,js文件在output的时候设置filename,加入[contenthash],可以让缓存命中加快。
静态资源加hash后缀,根据内容计算hash,文件内容不变,则hash不变,url不变,url和文件不变,则会自动触发http缓存机制,返回304。
SSR服务端渲染:将网页和数据一起加载,一起渲染。
非SSR(前后端分离):先加载网页,在加载数据,再重新渲染数据。(比如早期的JSP,ASP,PHP,现在的vue/React SSR)
Object.create()和new的区别
首先,Object.create()有两个参数:
1.proto:必选,是新建对象的原型对象。
2.propertisObject:可选,是新创建的实例对象上的属性。
// 首先,Object.create()有两个参数:
// 1.proto:必选,是新建对象的原型对象。
// 2.propertisObject:可选,是新创建的实例对象上的属性。
var x = Object.create({
a: 'A',
b: 'B',
c: 'C'
})
console.log(x) //{}
console.log(x.__proto__) //可以看到abc
var xx = Object.create({
a: 'A',
b: 'B',
c: 'C'
}, { //第二个属性相当于Object.defineProperty()
'a11': {
value: 'A11'
},
'b11': {
value: 'B11'
}
})
console.log(xx)
var AObj = {
a: 'A',
b: 'B',
c: function () {
console.log('C')
}
}
var _AObj = Object.create(AObj, {
'text': {
value: 'Object.create方法实现的继承'
}
})
console.log(_AObj)
_AObj.c()
// 这里可以看到_AObj的__proto__指向的就是他的父类
// 而new操作符,它创建的实例的__proto__是自动指向构造函数的prototype的
再回顾一下new操作符到底做了什么
1.创建一个新对象。
2.将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
3.执行构造函数中的代码(也就是为新对象添加属性)
4.返回新对象
// 用Object.create来模拟实现new关键字
let Parent = function (a) {
this.a = a;
}
Parent.prototype.Im = function () {
console.log(this.a)
}
let myNew = function (Parent, ...rest) {
let child = Object.create(Parent.prototype)
Parent.apply(child, rest)
return child
}
let child1 = myNew(Parent, 'gary')
child1.Im()