页面加载和渲染过程,性能优化问题,安全问题
1、js运行环境
运行环境即浏览器(server端有nodejs)
浏览器要下载网页代码,渲染出页面,期间会执行若干JS
要保证代码在浏览器中:稳定且高效
2、网页加载过程
加载资源的形式 :html代码,
媒体文件,如图片、视频等
javascript
css
加载资源的过程:DNS解析:域名--->IP地址
浏览器根据IP地址向服务器发起http请求
服务器处理http请求,并返回给浏览器
渲染资源的过程:根据HTML代码生成--->DOM Tree
根据css代码 ----> CSSOM
将DOM Tree 和 CSSOM整合Render Tree
根据Render Tree渲染页面
遇到<script>则暂停渲染,优先加载并执行JS代码,完成再继续(DOM渲染和js执行公用一个线程)
直至把Render Tree渲染完成
引出问题:
1、从输入url到渲染出页面的整个过程?
2、window.load和DOMContentLoaded的区别?
<img id="img" src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1594278708278&di=1c8a248fd269ca7495b65c017fe8ba0e&imgtype=0&src=http%3A%2F%2Fa3.att.hudong.com%2F14%2F75%2F01300000164186121366756803686.jpg" alt=""> <script> var img= document.getElementById('img') img.onload=function(){ console.log('img load') //2 } window.addEventListener('load',function(){ //页面资源全部加载完成,包括图片、视频等 console.log('all load') //3 }) document.addEventListener('DOMContentLoaded',function(){ // DOM 渲染完成即可执行,此时图片、视频可能还没有加载完 console.log('dom load') //1 }) </script>
3、为什么要把css放在head中?
4、为什么要把js放在body最下面?
3、性能优化
性能优化原则: 多使用内存、缓存或其他方法
减少CPU计算量,减少网络加载耗时
( 适用于所有编程的性能优化-----空间换时间,chrome浏览器就是个典型,每个标签页一个进程,每个标签互不干扰,空间大了,性能也提上去了)
从何入手:让加载更快
减少资源体积:压缩代码(webpack的mode:production)
减少访问次数:合并代码:webpack
SSR服务器渲染:将网页和数据一起加载,一起渲染
非SSR(前后端分离):先加载网页,在加载数据,再渲染数据
最早的JSP ASP PHP,现在的vue React SSR
缓存( 静态资源加hash后缀,根据文件内容计算hash
文件内容不变,则hash不变,则url不变
url 和 文件不变,则自动触发http缓存机制,返回304
)
使用更快的网络:CDN
让渲染更快
Css放在head,JS放在body最下面
尽早开始执行JS,用DOMContentLoaded触发
懒加载(图片懒加载,上滑加载更多),现在vue和react中可以只用插件
将页面里所有img属性src属性用data-xx代替,当页面滚动直至此图片出现在可视区域时,用js取到该图片的data-xx的值赋给src
<img id="img1" src="preview.png" data-realsrc="abc.png" alt=""> <script> var img1 = document.getElementById('img1') img1.src = img1.getAttribute('data-realsrc') </script>
对DOM操作查询进行缓存
var pList = document.getElementsByTagName('p') const length = pList.length for(i=0;i<length;i++){ //缓存length,只进行一次DOM查询 }
频繁DOM操作,合并到一起插入DOM结构
节流throttle 防抖 debounce 让渲染更流畅
// 防抖 // 监听输入框,文字变化后触发change事件 // 直接keyup,则会频繁触发onchange var input = document.getElementById('input') // 实现功能 let timer = null input.addEventListener('keyup',function(){ if(timer){ clearTimeout(timer) } timer = setTimeout(()=>{ console.log(input.value) timer=null },500) }) // 可以封装起来 function deboundce(fn,delay){ // timer实在闭包中 let timer = null; return function(){ if(timer){ clearTimeout(timer) } timer = setTimeout(()=>{ fn.apply(this,arguments) timer=null },delay) } } input.addEventListener('keyup',deboundce(()=>{ console.log(input.value) },500))
// 节流 // 拖拽一个元素的时候,要随时拿到该元素被拖拽的位置 // 直接用drag事件,则会频繁触发,很容易导致卡顿 const div1 = document.getElementById('drag') let timer = null div1.addEventListener('drag',function(e){ if(timer){ return } timer = setTimeout(()=>{ console.log(e.offsetX) timer=null },100) }) function throlle(fn,delay){ var timer=null; return function(){ if(timer){ return } timer = setTimeout((e)=>{ fn.apply(this,arguments) timer=null },500) } } div1.addEventListener('drag',throlle(function(e){ console.log(e.offsetX) },500))
4、安全
XSS
XSRF