运行环境
- 运行环境即浏览器(server端有nodejs)
- 下载网页代码,渲染出页面,期间会执行若干JS
- 要保证代码在浏览器中:稳定且高效
要知道的知识点
- 网页加载过程
- 性能优化
- 安全
面试相关题目
- 从输入url到渲染出页面的整个过程
- window.onload和DOMContentLoaded的区别
知识点及讲解
-
加载资源的形式
- html代码
- 媒体文件,如图片,视频等
- javascript css
-
加载资源的过程
- DNS解析:域名-->IP地址
- 浏览器根据IP地址向服务器发起http请求
- 服务器处理http请求,并返回给浏览器
-
渲染页面的过程
- 根据HTML代码生成DOM Tree
- 根据CSS代码生成CSSOM
- 将DOM Tree 和CSSOM整合形成Render Tree
- 根据Render Tree渲染页面
- 遇到
<script>则暂时渲染,优先加载执行JS代码,完成再继续 - 直至把Render Tree渲染完成
建议把css放到<head>中;
建议把JS放到<body>最后;
window.addEventListener('load',function(){
//页面的全部资源加载完才会执行,包括图片,视频等
})
document.addEventListener('DOMContentLoaded',function(){
//DOM 渲染完即可执行,此时图片,视频还可能没有加载完
})
题解:
- 从输入url到渲染出页面的整个过程
- 下载资源:各个资源类型,下载过程
- 渲染页面:结合html css javascript图片等
- 结合上面的知识点讲解结合回答
- window.onload和DOMContentLoaded的区别
-
load: 页面的全部资源加载完才会执行,包括图片,视频等
-
DOMContentLoaded: DOM 渲染完即可执行,此时图片,视频还可能没有加载完
-
性能优化(防抖 节流)
性能优化原则
- 多使用内存、缓存或其他方法
- 减少CPU计算量,减少网络加载耗时
- (适用于所有编程的性能优化---空间换时间) 从何入手?:
- 让加载更快
- 减少资源体积:压缩代码
- 减少访问次数:合并代码,SSR服务器端渲染,缓存
- 使用更快的网络:CDN
- 让渲染更快
- css放到
<head>中;JS放到<body>最下面 - 尽早开始执行JS,用DOMContentLoaded触发
- 懒加载(图片懒加载,上滑加载更多)
- 对DOM查询进行缓存
- 频繁DOM操作,合并到一起插入DOM结构
- 节流throttle,防抖debounce
- css放到
面试相关题目
- 手写防抖、手写节流
代码示例
资源合并
<script src="a.js"></script>
<script src="b.js"></script>
<script src="c.js"></script>
三合一变成一个文件,减少网络请求
<script src="abc.js"></script>
缓存
- 静态资源加hash后缀,根据文件内容计算hash
- 文件内容不变,则hash不变,则url不变
- url和文件不变,则会自动触发http缓存机制,返回304
module.exports = {
mode:'production',
entry:path.join(__dirname,'src','index'),
output:{
filename:'bundle.[contenthash].js',
path:path.join(__dirname,'dist')
}
}
CDN
SSR
- 服务器端渲染:将网页和数据一起加载,一起渲染
- 非SSR(前后端分离):先加载网页,再加载数据,再渲染
- 早先的JSP ASP PHP,现在的vue React SSR
懒加载
把图片先用个预览图片代替,当图片露出屏幕时再真正加载
<img id="img1" src="preview.png" data-realsrc="abc.png" />
<srcipt type="text/javascript">
var img1 = document.getElementById('img1');
img1.src = img1.getAttribute('data-realsrc');
</script>
缓存DOM查询
//不缓存DOM查询结果
for(let i = 0; i < document.getElementsByTagName('p').length;i++){
//每次循环,都会计算length,频繁进行DOM查询
}
//缓存DOM查询结果
const pList = document.getElementsByTagName('p')
const length = pList.length;
for(let i = 0; i < length; i++){
//缓存length,只进行一次DOM查询
}
多个DOM操作一起插入到DOM结构
const listNode = document.getElementById('list')
//创建一个文档片段,此时还没有插入到DOM树中
const frag = document.createDocumentFragment()
//执行插入
for(let x = 0; x < 10; x++){
const li = document.createElement("li");
li.innerHTML = "List item" + x;
frag.appendChild(li);
}
//都完成之后,再插入到DOM树中
listNode.appendChild(frag);
尽早开始执行JS
window.addEventListener('load',function(){
//页面的全部资源加载完才会执行,包括图片,视频等
})
document.addEventListener('DOMContentLoad',function(){
//DOM渲染完即可执行,此时图片、视频还可能没有加载完
})
防抖debounce
- 监听一个输入框的,文字变化后触发change事件
- 直接用keyup事件,则会频繁触发change事件
- 防抖:用户输入结束或暂停时,才会触发change事件
在实践经验中,因为没用防抖,导致用复杂正则较难输入框快速输入内容时卡壳
文件index.html
<!DICTYPE html>
<html lang="en">
<body>
<input type="text" id="input1">
<script src="./debounce.js"></script>
</body>
</html>
文件debounde.js
const input1 = document.getElementById('input1')
let timer = null;
/*input1.addEventListener('keyup',function(){
if(timer){
clearTimeout(timer);
}
timer = setTimeout(()=>{
//模拟触发change事件
console.log(input1.value);
//清空定时器
timer = null;
},500)
})*/
//封装
function debounce(fn, delay = 500){
//timer 是闭包中的
let timer = null;
return function(){
if(timer){
clearTimeout(timer);
}
timer = setTimeout(()=>{
fn.apply(this,arguments);
timer = null;
},delay)
}
}
input1.addEventListener('keyup',debounce(function(){
console.log(input1.value);
},600))
节流throttle
- 拖拽一个元素时,要随时拿到该元素被拖拽的位置
- 直接用drag事件,则会频繁触发,很容易导致卡顿
- 节流:无论拖拽速度多快,都会每隔100ms触发一次
const div1 = document.getElementById('div1');
let timer = null;
/*div1.addEventListener('drag',function(e){
console.log(e.offsetX,e.offsetY);
if(timer){
return;
}
timer = setTimeout(()=>{
console.log(e.offsetX,e.offsetY);
timer = null;
},100)
})*/
function throttle(fn,delay = 100){
let timer = null;
return function(){
if(timer){
return;
}
timer = setTimeout(()=>{
fn.apply(this,arguments);
timer = null;
},delay)
}
}
div1.addEventListener('drag',throttle(function(e){
console.log(e.offsetX,e.offsetY);
}))
安全
问题:常见的WEB前端攻击方式有哪些?
- XSS跨站请求攻击
- XSRF跨站请求伪造
XSS跨站请求攻击
- 一个博客网站,我发表一篇博客,其中嵌入
<script>脚本 - 脚本内容:获取cookie,发送到我的服务器(服务器配合跨站)
- 发布这篇博客,有人查看它,我轻松收割访问者的cookie
XSS预防
- 替换特殊字符,如
<变为<;>变为> <script>变成<script>,直接显示,而不会作为脚本执行- 前端要替换,后端也要替换,都做总不会有错
如
~~~
<script>alert(document.cookie);</script>
换成 <script>alert(document.cookie); </script>
有xss替换工具,npm可下载 https://www.npmjs.com/package/xss
~~~
XSRF跨站请求伪造
XSRF攻击
- 你正在购物,看中了某个商品,商品ID是100
- 付费接口是xxx.com/pay?id=100,但是没有任何验证
- 我是攻击者,我看中了一个商品,ID是200
- 我向你发送一封电子邮件,邮件标题很吸引人
- 但邮件正文隐藏着`<img src=xxx.com/pay?id=200 />
- 你一查看邮件,就帮我购买了id是200的商品
XSRF预防
- 使用post接口
- 增加验证,例如密码、短信验证码、指纹等