HTML
1.HTML5有哪些语义化标签
HTML5的语义化指的是合理正确的使用语义化的标签来创建页面结构。代码结构清晰,易于阅读,利于开发和维护,方便其他设备解析(如屏幕阅读器)根据语义渲染网页。有利于搜索引擎优化(SEO),搜索引擎爬虫会根据不同的标签来赋予不同的权重。
- header:定义页眉信息
- nav:导航栏
- section:页面的组成部分
- footer:脚注信息
- aside:侧边栏信息,比如菜单或者广告等
- main(页面主要内容)
- dialog(加载对话框标签)
- video(加载视频)
- audio(加载音频【支持ogg、mp3、wav格式】)
2.对浏览器内核的理解:
浏览器内核主要分成两部分:渲染引擎和JS引擎。
渲染引擎:决定了浏览器如何加载和显示网页的内容以及信息。负责取得网页的内容(HTML、XML、图像等等)、整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至显示器。浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不相同。
JS引擎:解析和执行javascript来实现网页的动态效果。最开始渲染引擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎。
CSS
1.什么是 BFC
BFC 块级格式化上下文 一块独立的区域,有自己的规则,bfc中的元素与外界的元素互不影响。BFC是一块用来独立的布局环境,保护其中内部元素不受外部影响,也不影响外部。
- 怎么触发BFC
- float的值left或right
- overflow的值不为visible(默认)
- display的值为inline-block、table-cell、table-caption
- position的值为absolute(绝对定位)或fixed固定定位
- BFC的应用
- 1、可以用来自适应布局
利用BFC的这个原理可以实现两栏布局,左边定宽,右边自适应。不会相互影响,哪怕高度不相等。
给左边盒子加浮动,右边盒子加overflow:hidden;变成BFC,就可以消除外部左边盒子因浮动对他的影响
- 2、可以清除浮动
一个父元素中的子元素,设置浮动时,父元素没有设置高度,这时子元素脱离文档流,
父元素感知不到子元素的高度,造成父元素的塌陷。
这时候给父元素添加overflow:hidden / auto,变成BFC就可以解决这种问题。
- 3、解决垂直边距重叠 1.父子关系的边距重叠
父子关系,如果子元素设置了外边距,在没有把父元素变成BFC的情况下,父元素也会产生外边距。
解决办法: 是给父元素添加一个 overflow:hidden,这样父元素就变为BFC,
不会随子元素产生外边距
2.同级兄弟关系的重叠
同级元素在垂直方向上外边距会出现重叠现象,最后外边距的大小取两者绝对值大的那个
可通过添加一个空元素或伪类元素,设置overflow:hidden;解决
2.伪类和伪元素及使用场景
伪类:当元素处于特定状态时才会运用的特殊类,开头为冒号的选择器,用于选择处于特定状态的元素。比如:first-child选择第一个子元素;:hover悬浮在元素上会显示;:focus用键盘选定元素时激活;
伪元素
伪元素用于创建一些不在文档树中的元素,并为其添加样式。比如说,我们可以通过::before 来在一个元素前增加一些文本,并为这些文本添加样式。虽然用户可以看到这些文本,但是这些文本实际上不在文档树中。
3.src 和 href 区别
- href表示超文本引用,指向网络资源所在位置。href 用于在当前文档和引用资源之间确立联系
- src目的是要把文件下载到html页面中去。src 用于替换当前内容。
- 浏览器解析方式,当浏览器遇到href会并行下载资源并且不会停止对当前文档的处理。(同时也是为什么建议使用 link 方式加载 CSS,而不是使用 @import 方式) 当浏览器解析到src ,会暂停其他资源的下载和处理,直到将该资源加载或执行完毕。(这也是script标签为什么放在底部而不是头部的原因)
4. flex布局
flex布局
就是弹性布局,任何一个容器都可以指定为Flex布局。
注意:设为Flex布局后,子元素的float、clear和vertical-align属性将失效。
容器的常用属性(父元素)
容器相当于父元素,即用在父元素上的属性,有下面6个:
- flex-direction 设置主轴的方向
- flex-wrap 控制项目(子元素)是否换行
- flex-flow 是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap
- justify-content 设置主轴上的子元素对齐方式
- align-items 定义项目在交叉轴上如何对齐
- align-content 属性定义了多根轴线的对齐方式,前提是需要设置flex-wrap: wrap,否则不会有效
项目的属性(子元素) 有下面6个(都是给子元素加的属性):
- order 定义项目的排列顺序。数值越小,排列越靠前,默认为0
- flex-grow flex容器中剩余空间的多少应该分配给项目,也称为扩展规则
- flex-shrink 属性指定了 flex 元素的收缩规则
- flex-basis 指定了子项在容器主轴方向上的初始大小,优先级高于自身的宽度width
- flex 是
flex-grow,flex-shrink和flex-basis的简写,默认值为0 1 auto。后两个属性可选- align-self 属性允许单个项目有与其他项目不一样的对齐方式,可覆盖
align-items属性
5.水平垂直居中
- 需要知道子元素的宽高
方式1
.wp {
position: relative;
}
.box {
position: absolute;;
top: 50%;
left: 50%;
margin-left: -50px;
margin-top: -50px;
}
方式2
.wp {
position: relative;
}
.box {
position: absolute;;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
方式3
.wp {
position: relative;
}
.box {
position: absolute;;
top: calc(50% - 50px);
left: calc(50% - 50px);
}
- 不需要子元素固定宽高
.wp {
position: relative;
}
.box {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
- flex
<div class="wp">
<div class="box">123123</div>
</div>
.wp {
display: flex;
justify-content: center;
align-items: center;
}
5.定位有哪几种?分别举例?
- static: 默认值 没有定位,元素出现在正常的流中
- relative(相对定位):生成相对定位的元素,相对于其正常(原先本身)位置进行定位
- absolute(绝对定位):生成绝对定位的元素,相对于static定位以外的第一个父元素进行定位
- fixed(固定定位):生成绝对定位的元素,相对于浏览器窗口进行定位
- sticky 粘性定位 当前元素设置了粘性定位,滚动到顶部就会吸附顶部,往下滑还回到原来位置。
6.link和@import的区别
1.从属关系: link是标签,@import是css提供的.
2.加载差异: link: 结构和样式同时加载;而@import 先加载结构,后加载样式
3.兼容性:link没有兼容问题,@import不兼容ie5以下的浏览器.
4.可操作性: link可以通过js操作dom插入link标签改变样式,而@import不能
7.什么是重排什么是重绘以及区别
重排:
当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为重排(reflow)。每个页面至少需要一次重排,就是在页面第一次加载的时候,这时候是一定会发生重排的,因为要构建render tree.
重绘:
当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘.
区别:
重排必将引起重绘,而重绘不一定会引起重排。比如:只有颜色改变的时候就只会发生重绘而不会引起重排,当页面布局和几何属性改变时就需要重排
8.浏览器是如何渲染页面的
浏览器将获取的HTML文档解析成DOM树。CSS则被CSS解析器解析成CSSOM 树。将DOM和CSSOM合并为渲染树(rendering tree),代表一系列将被渲染的对象。渲染树的每个元素包含的内容都是计算过的,它被称之为布局layout。浏览器使用一种流式处理的方法,只需要一次绘制操作就可以布局所有的元素。 将渲染树的各个节点绘制到屏幕上,这一步被称为绘制painting。
- 构建对象模型(DOM,CSSOM)
- 构建渲染树(RenderTree)
- 布局
- 渲染
9.less和scss的用法与区别
变量、嵌套、计算
- 声明和使用变量,LESS用@符号,SCSS用$符号表示
@link-color:#632bca
$to-color:#632bca
.main{
color:@link-color //#632bca颜色LESS
background-color:$to-color //#632bca颜色SCSS
}
- 变量插值,LESS采用@{XXXX}的形式,SCSS采用${XXXX}的形式,作用:可以用为LESS和SCSS声明变量,变量作为css的选择器
//LESS
@main-top : search;
.@{ main-top } {
font-size : 24px;
color : #fff;
}
// 是用LESS,定义类,类选择器选中search标签,给其设置css样式
// SCSS
$main-top : search;
.@{ main-top } {
font-size : 24px;
color : #fff;
}
// 是用scss,定义类,类选择器选中search标签,给其设置css样式
- SCSS支持条件语句,LESS不支持,SCSS可以使用if{}else,for循环等等,LESS不支持
- 应用外部css文件方式不同,SCSS应用的css文件名必须以‘_’开头(下划线),文件名如果以下划线开头的话,sass会认为该文件是一个应用文件,不会将它转成css文件
浏览器和网络篇
1.跨页面通信的方法-同源和不同源
这里分了同源页面和不同源页面的通信。
不同源页面可以通过 iframe 作为一个桥梁,因为 iframe 可以指定 origin 来忽略同源限制,所以可以在每个页面都嵌入同一个 iframe 然后监听 iframe 中传递的 message 就可以了。
同源页面的通信大致分为了三类:广播模式、共享存储模式和口口相传模式
第一种广播模式,就是可以通过 BroadCast Channel、Service Worker 或者 localStorage 作为广播,然后去监听广播事件中消息的变化,达到页面通信的效果。
第二种是共享存储模式,我们可以通过Shared Worker 或者 IndexedDB,创建全局共享的数据存储。然后再通过轮询去定时获取这些被存储的数据是否有变更,达到一个的通信效果。像常见cookie 也可以作为实现共享存储达到页面通信的一种方式
最后一种是口口相传模式,这个主要是在使用 window.open 的时候,会返回被打开页面的 window 的引用,而在被打开的页面可以通过 window.opener 获取打开它的页面的 window 点引用,这样,多个页面之间的 window 是能够相互获取到的,传递消息的话通过 postMessage 去传递再做一个事件监听就可以了
2.跨域常用方案-协议-域名-端口
什么是跨域?
协议 + 域名 + 端口号均相同时则为同域,任意一个不同则为跨域
解决方案
- 1.jsonp
利用<script>标签没有跨域限制的漏洞,网页可以得到从其他来源动态产生的 JSON 数据。JSONP请求一定需要对方的服务器做支持才可以。 - 2.cors
CORS 需要浏览器和后端同时支持。IE 8 和 9 需要通过 XDomainRequest 来实现。
浏览器会自动进行 CORS 通信,实现 CORS 通信的关键是后端。只要后端实现了 CORS,就实现了跨域。
服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。 该属性表示哪些域名可以访问资源,如果设置通配符则表示所有网站都可以访问资源。
虽然设置 CORS 和前端没什么关系,但是通过这种方式解决跨域问题的话,会在发送请求时出现两种情况,分别为简单请求和复杂请求。 - 3.postMessage
postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:
页面和其打开的新窗口的数据传递 多窗口之间消息传递 页面与嵌套的iframe消息传递 上面三个场景的跨域数据传递
postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。 - websocket
Websocket是HTML5的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。WebSocket和HTTP都是应用层协议,都基于 TCP 协议。但是 WebSocket 是一种双向通信协议,在建立连接之后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据。同时,WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了 - Node中间件代理(两次跨域)
实现原理:同源策略是浏览器需要遵循的标准,而如果是服务器向服务器请求就无需遵循同源策略。 代理服务器,需要做以下几个步骤:
接受客户端请求 。
将请求转发给服务器。
拿到服务器响应数据。
将响应转发给客户端 - 6.nginx反向代理
实现原理类似于Node中间件代理,需要你搭建一个中转nginx服务器,用于转发请求。
使用nginx反向代理实现跨域,是最简单的跨域方式。只需要修改nginx的配置即可解决跨域问题,支持所有浏览器,支持session,不需要修改任何代码,并且不会影响服务器性能。
实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录
3.强制缓存-协商缓存-详细说说HTTP缓存
在浏览器第一次发起请求服务的过程中,会根据响应报文中的缓存标识决定是否缓存结果,是否将缓存标识和请求结果存入到浏览器缓存中。
HTTP 缓存分为强制缓存和协商缓存两类。
强制缓存就是请求的时候浏览器向缓存查找这次请求的结果,这里分了三种情况,没查找到直接发起请求(和第一次请求一致);查找到了并且缓存结果还没有失效就直接使用缓存结果;查找到但是缓存结果失效了就会使用协商缓存。
协商缓存就是强制缓存的缓存结果失效了,浏览器携带缓存标识向服务器发起请求,服务器通过缓存标识决定是否使用缓存的过程。
4.输入 URL 到页面展现的全过程
- 用户在浏览器中输入url地址
- 浏览器解析域名得到服务器ip地址,浏览器会从缓存中找是否存在域名,如果存在就直接取出对应的ip地址,如果没有就开启一个DNS域名解析器。DNS域名解析器会访问域名服务器,将对应的ip发给客户端;然后访问根域名解析器,将对应的ip发给客户端;最后访问本地域名服务器,得到最终的ip地址。
- TCP三次握手建立客户端和服务器的连接,因为HTTP是基于TCP的可靠传输,所以在发送http数据报之前,需要先进行TCP的三次握手建立连接。 第一次握手:客户端--->服务端 ack=1,seq=x(x随机生成) 第二次握手:服务端--->客户端 ACK=1,ack=x+1,seq=y(y随机生成) 第三次握手:客户端--->服务端 ACK=1,ack=y+1,seq=x+1 完成第三次握手时,实际上客户端已经与服务器建立了连接,所以第三次握手的报文已经可以携带数据了。
- 客户端发送HTTP请求获取服务器端的静态资源
- 服务器发送HTTP响应报文给客户端,客户端获取到页面静态资源
- TCP四次挥手关闭客户端和服务器的连接,数据传输完毕后,TCP会进行四次挥手断开连接,释放资源。第一次挥手:客户端--->服务器 FIN=1,ack=1,seq=u 客户端状态变为FIN_WAIT_1,第二次挥手:服务器--->客户端 ACK=1,ack=u+1,seq=v 服务器状态变为CLOSE_WAIT,TCP进入半关闭状态,第三次挥手:服务器--->客户端 FIN=1,ACK=1,ack=u+1,seq=w 服务器状态变为LAST_ACK。第四次挥手:客户端--->服务器 ACK=1,ack=w+1,seq=u+1 客户端状态变为TIME_WAIT,此时TCP未释放,需要等待计时器计时完成后,客户端状态变为CLOSED
- 浏览器解析文档资源并渲染页面 浏览器解析文档资源并渲染页面流程: (1)解析html资源,构建DOM Tree (2)解析css资源,构建CSS Rule Tree (3)JS通过DOM API和CSS OM API来操作DOM Tree和CSS Tree (4)解析完成后综合DOM Tree和CSS Tree会生成Render Tree,计算每个元素的位置,这个过程就是回流(layout or reflow) (5)调用操作系统Native GUI的绘制 (6)页面绘制完成
5.TCP 和 UDP 的区别
UDP 是用户数据包协议,IP 通过 IP 地址信息把数据包传送给指定电脑后,UDP 可以通过端口号把数据包分发给正确的程序。UDP 可以校验数据是否正确,但没有重发的机制,只会丢弃错误的数据包,同时 UDP 在发送之后无法确认是否到达目的地。UDP 不能保证数据的可靠性,但是传输的速度非常快,通常运用于在线视频、互动游戏这些不那么严格保证数据完整性的领域。
TCP 是为了解决 UDP 的数据容易丢失,且无法正确组装数据包而引入的传输控制协议,是一种面向连接的,可靠的,基于字节流的传输层通信协议。TCP 在处理数据包丢失的情况,提供了重传机制;并且 TCP 引入了数据包排序机制,可以将乱序的数据包组合成完整的文件。
TCP 头除了包含目标端口和本机端口号外,还提供了用于排序的序列号,以便接收端通过序号来重排数据包。
一个 TCP 连接的生命周期会经历链接阶段,数据传输和断开连接阶段三个阶段。
连接阶段
用来建立客户端和服务器之间的链接,通过三次握手用来确认客户端、服务端相互之间的数据包收发能力。
1、客户端先发送 SYN 报文用来确认服务端能够发数据,并进入 SYN_SENT 状态等待服务端确认
2、服务端收到 SYN 报文,会向客户端发送一个 ACK 确认报文,同时服务端也会向客户端发送 SYN 报文用来确认客户端是否能够发送数据,此时服务端进入 SYN_RCVD 状态
3、客户端接收到 ACK + SYN 的报文,就会向服务端发送数据包并进入 ESTABLISHED 状态(建立连接);服务端接收到客户端发送的 ACK 包也会进入 ESTABLISHED 状态,完成三次握手
传输数据阶段
该阶段,接收端需要对每个包进行确认操作;
所以当发送端发送了一个数据包之后,在规定时间内没有接收到接收端反馈的确认消息,就会判断为包丢失,从而触发重发机制;
一个大文件在传输过程中会分为很多个小数据包,数据包到达接收端后会根据 TCP 头中的序号为其排序,保证数据的完整。
断开连接阶段
通过四次挥手,来保证双方的建立的连接能够断开
1、客户端向服务器发起 FIN 包,并进入 FIN_WAIT_1 状态
2、服务端收到 FIN 包,发出确认包 ACK,并带上自己的序号,服务端进入 CLOSE_WAIT 状态。这时候客户端已经没有数据要发给服务端了,但是服务端如果有数据要发给客户端,客户端还是需要接收。客户端收到 ACK 后进入 FIN_WAIT_2 状态
3、服务端数据发送完毕后,向客户端发送 FIN 包,此时服务器进入 LAST_ACK 状态
4、客户端收到 FIN 包发出确认包 ACK ,此时客户端进入 TIME_WAIT 状态,等待 2 MSL 后进入 CLOSED 状态;服务端接收到客户端的 ACK 后就进入 CLOSED 状态了。
对于四次挥手,因为 TCP 是全双工通信,在主动关闭方发送 FIN 包后,接收端可能还要发送数据,不能立即关闭服务器端到客户端的数据通道,所以也就不能将服务器端的 FIN 包与对客户端的 ACK 包合并发送,只能先确认 ACK,然后服务器待无需发送数据时再发送 FIN 包,所以四次挥手时必须是四次数据包的交互
6.Content-length 了解吗?
Content-length 是 http 消息长度,用十进制数字表示的字节的数目。
如果 content-length > 实际长度,服务端/客户端读取到消息队尾时会继续等待下一个字节,会出现无响应超时的情况
如果 content-length < 实际长度,首次请求的消息会被截取,然后会导致后续的数据解析混乱。
7.XSS 和 CSRF
xss基本概念Xss 跨站脚本攻击,为了和 css 区别开来所以叫 xss
Xss 指黑客向 html 或 dom 中注入恶意脚本,从而在用户浏览页面的时候利用注入脚本对用户实施攻击的手段
恶意脚本可以做到:窃取 cookie 信息、监听用户行为(比如表单的输入)、修改DOM(比如伪造登录界面骗用户输入账号密码)、在页面生成浮窗广告等
恶意脚本注入方式:
- 存储型 xss
黑客利用站点漏洞将恶意 js 代码提交到站点服务器,用户访问页面就会导致恶意脚本获取用户的cookie等信息。 - 反射性 xss
用户将一段恶意代码请求提交给 web 服务器,web 服务器接收到请求后将恶意代码反射到浏览器端 - 基于 DOM 的 xss 攻击通过网络劫持在页面传输过程中更改 HTML 内容
前两种属于服务端漏洞,最后一种属于前端漏洞
防止xss攻击的策略
1、服务器对输入脚本进行过滤或者转码,比如将code:<script>alert('你被xss攻击了')</script>转换成code:<script>alert('你被xss攻击了')</script>
2、充分利用内容安全策略 CSP(content-security-policy),可以通过 http 头信息的 content-security-policy 字段控制可以加载和执行的外部资源;或者通过html的meta 标签<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">
3、cookie设置为 http-only, cookie 就无法通过document.cookie来读取
csrf基本概念Csrf(cross site request forgery)跨站请求伪造,指黑客引导用户访问黑客的网站。
CSRF 是指黑客引诱用户打开黑客的网站,在黑客的网站中,利用用户的登录状态发起的跨站请求。简单来讲,CSRF 攻击就是黑客利用了用户的登录状态,并通过第三方的站点来做一些坏事。
8.websocket
websocket是一种支持双向通信的协议,就是服务器可以主动向客户端发消息,客户端也可以主动向服务器发消息。它是基于 HTTP 协议来建立连接的的,与http协议的兼容性很好,所以能通过 HTTP 代理服务器;没有同源限制。WebSocket 是一种事件驱动的协议,这意味着可以将其用于真正的实时通信。与 HTTP 不同(必须不断地请求更新),而使用 websockets,更新在可用时就会立即发送。当连接终止时,WebSockets 不会自动恢复,这是应用开发中需要自己实现的机制,也是存在许多客户端开源库的原因之一。像webpack和vite的devServer就使用了websocket实现热更新
9.Post 和 Get 区别
- 应用场景: 一般 Get 请求用于对服务器资源不会产生影响的场景,比如说请求一个网页的资源。而Post一般用于对服务器资源会产生影响的情景,比如注册用户这一类的操作。
- 是否缓存: 因为两者应用场景不同,浏览器一般会对 Get 请求缓存,但很少对 Post 请求缓存。
- 传参方式不同: Get 通过查询字符串传参,Post 通过请求体传参。
- 安全性: Get 请求可以将请求的参数放入 url 中向服务器发送,这样的做法相对于 Post 请求来说是不太安全的,因为请求的 url 会被保留在历史记录中。
- 请求长度: 浏览器由于对 url 长度的限制,所以会影响 get 请求发送数据时的长度。
- 参数类型: get参数只允许字符,post 的参数传递支持更多的数据类型(如文件、图片)。
post请求会发送两次请求
1.第一次请求为options预检请求,状态码为:204。2.第二次为真正的post请求
10.cookie、localStorage、sessionStorage的区别
浏览器的本地存储主要分为Cookie、localStorage和sessionStorage。
共同点: 都是保存在浏览器端、且同源的
不同点:
cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。sessionStorage和localStorage不会自动把数据发送给服务器,仅在本地保存。
存储大小限制也不同,cookie数据不能超过4K,sessionStorage和localStorage可以达到5M.
- sessionStorage:仅在当前浏览器窗口关闭之前有效;
- localStorage:始终有效,窗口或浏览器关闭也一直保存,本地存储,因此用作持久数据;
- cookie:只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭
作用域不同 - sessionStorage:不在不同的浏览器窗口中共享,即使是同一个页面;
- localstorage:在所有同源窗口中都是共享的;也就是说只要浏览器不关闭,数据仍然存在
- cookie: 也是在所有同源窗口中都是共享的.也就是说只要浏览器不关闭,数据仍然存在
性能优化篇
1.性能优化有哪些手段
- 从缓存的角度
- 将一些不常变的大数据通过localstorage/sessionStorage 进行读取
- 活用 http 缓存(强缓存和协商缓存),将内容存储在内存或者硬盘中,减少对服务器端的请求
- 网络方面比较常用的是静态资源使用 CDN
- 打包方面
路由的按需加载- 优化打包后资源的大小
- 开启 gzip 压缩资源
按需加载三方库
- 代码层面
减少不必要的请求,删除不必要的代码- 避免耗时过长的js处理阻塞主线程(耗时且无关 DOM 可以丢到web worker去处理或者拆分成小的任务)
图片可以使用懒加载的方式,长列表使用虚拟滚动
- 首屏速度提升
- 代码压缩,减少打包的静态资源体积(Terser plugin/MiniCssExtratplugin)
- 路由懒加载,首屏就只会请求第一个路由的相关资源
- 使用 cdn加速第三方库,我们是toB的产品,会需要部署在内网,所以一般不用,toC用的多
ssr 服务端渲染,由服务器直接返回拼接好的html页面
- vue 常见的性能优化方式
- 图片懒加载: vue-lazyLoad
- 虚拟滚动
- 函数式组件
v-show/ keep-alive 复用 dom- deffer延时渲染组件(requestIdleCallback)
- 时间切片 time slicing
2.前端监控 SDK 技术要点
- 可以通过
window.performance获取各项性能指标数据 - 完整的前端监控平台包括:数据采集和上报、数据整理和存储、数据展示
3.大图片优化的方案
- 优化请求数
雪碧图,将所有图标合并成一个独立的图片文件,再通过background-url和backgroun-position来显示图标- 懒加载,尽量只加载用户正在浏览器或者即将浏览的图片。最简单使用监听页面滚动判断图片是否进入视野;使用css的
background-url来懒加载 - base64,小图标或骨架图可以使用内联 base64因为 base64相比普通图片体积大。注意首屏不需要懒加载,设置合理的占位图避免抖动。
- 减小图片大小
- 使用合适的格式比如WebP、svg、video替代 GIF 、渐进式 JPEG
- 削减图片质量
- 使用合适的大小和分辨率
- 删除冗余的图片信息
- Svg 压缩
- 缓存
4.代码优化
- 非响应式变量可以定义在
created钩子中使用 this.xxx 赋值 - 访问局部变量比全局变量快,因为不需要切换作用域
- 尽可能使用
const声明变量,注意数组和对象 - 避免内存泄露的方式
- 尽可能少创建全局变量
- 手动清除定时器
- 少用闭包
- 清除 DOM 引用
- 避免强制同步,再修改 DOM 之前查询相关值
- 合理利用 css 合成动画,如果能用 css 处理就交给 css。因为合成动画会由合成线程执行,不会占用主线程
- 避免频繁的垃圾回收,优化存储结构,避免小颗粒对象的产生
前端工程化篇
1.webpack的执行流程和生命周期
webpack 是为现代 JS 应用提供静态资源打包功能的 bundle。
核心流程有三个阶段: 初始化阶段、构建阶段和生成阶段
1、初始化阶段,会从配置文件、配置对象和Shell参数中读取初始化的参数并与默认配置结合成最终的参数,以及创建 compiler 编译器对象和初始化它的运行环境
2、构建阶段,编译器会执行它的 run()方法开始编译的过程,其中会先确认 entry 入口文件,从入口文件开始搜索和入口文件有直接或者简介关联的所有文件创建依赖对象,之后再根据依赖对象创建 module 对象,这时候会使用 loader 将模块转换标准的 js 内容,再调用 js 的解释器将内容转换成 AST 对象,再从 AST 中找到该模块依赖的模块,递归本步骤知道所有入口依赖文件都经过了本步骤的处理。最后完成模块编译,得到了每个模块被翻译的内容和他们之间的关系依赖图。
3、生成阶段,将编译后的 module 组合成 chunk ,再把每个 chunk 转换成一个单独的文件输出到文件列表,确定好输出内容后,根据配置确定输出路径和文件名,就把文件内容写入文件系统
2.webpack的plugin 和loader
loader本质上就是个转换器,能将其他类型的文件转换成 webpack 识别的东西
loader 会在 webpack 的构建阶段将依赖对象创建的 module 转换成标准的 js 内容的东西。比如 vue-loader 将vue文件转换成 js 模块,图片字体通过 url-loader 转换成 data URL,这些 webpack 能够识别的东西。
可以在 module.rules 中配置不同的 loader 解析不同的文件
plugin插件本质是一个带有 apply 函数的类,这个apply 函数有个参数 compiler 是webpack 初始化阶段生成的编译器对象,可以调用编译器对象中的 hooks 注册各种钩子的回调这些 hooks 是贯穿整个编译的生命周期。比如stylelint plugin可以指定 stylelint 的需要检查文件类型和文件范围;HtmlWebpackPlugin 用来生成打包后的模板文件;MiniCssExtactPlugin会将所有的css提取成独立的chunks,stylelintplugin可以在开发阶段提供样式的检查功能。
3.webpack的hash策略
Webpack 内置 hash 有三种
- hash: 项目每次构建都会生成一个hash,和整个项目有关,项目任意地方有改变就会改变,hash会根据每次工程的内容进行计算,很容易造成不必要的hash变更,不利于版本管理。
- content hash: 和单个文件的内容相关。指定文件的内容发生改变,就会改变hash,内容不变hash 值不变。
- chunk hash:和webpack打包生成的chunk相关。每一个entry,都会有不同的hash。一般来说,针对于输出文件,我们使用chunkhash。因为webpack打包后,最终每个entry文件及其依赖会生成单独的一个js文件。此时使用chunkhash,能够保证整个打包内容的更新准确性。
4.vite原理
Vite 主要由两个部分组成
1.开发环境Vite 利用浏览器去解析 imports,在服务器端按需编译返回,完全跳过了打包这个概念,服务器随起随用。
2.生产环境使用 rollup 来构建代码,提供指令可以用来优化构建过程。
5.webpack 和 vite 对比
Webpack 的热更新原理简单来说就是,一旦发生某个依赖(比如 a.js )改变,就将这个依赖所处的 module 的更新,并将新的 module 发送给浏览器重新执行。每次热更新都会重新生成 bundle。
Vite 利用浏览器去解析 imports,在服务器端按需编译返回,完全跳过了打包这个概念,服务器随起随用,热更新是在客户端和服务端之间建立了 websocket 连接,代码修改后服务端发送消息通知客户端去请求修改模块的代码,完成热更新,就是改了哪个文件就重新请求那个文件,这样保证了热更新速度不受项目大小影响。
6.做过哪些 webpack 的优化
- 压缩代码:删除多余的代码、注释、简化代码的写法等等⽅式。可以利⽤webpack的 UglifyJsPlugin 和 ParallelUglifyPlugin 来压缩JS⽂件, 利⽤ cssnano (css-loader?minimize)来压缩css
- 利⽤CDN加速: 在构建过程中,将引⽤的静态资源路径修改为CDN上对应的路径。可以利⽤webpack对于 output 参数和各loader的 publicPath 参数来修改资源路径
- Tree Shaking: 将代码中永远不会⾛到的⽚段删除掉。可以通过在启动webpack时追加参数 --optimize-minimize 来实现
- Code Splitting (自动): 将代码按路由维度或者组件分块(chunk),这样做到按需加载,同时可以充分利⽤浏览器缓存
- 提取公共第三⽅库: SplitChunksPlugin插件来进⾏公共模块抽取,利⽤浏览器缓存可以⻓期缓存这些⽆需频繁变动的公共代码
7.npm run 执行过程
0、在 package.json 文件中可以定义 script 配置项,里面可以定义运行脚本的键和值
1、在 npm install 的时候,npm 会读取配置将执行脚本软链接到node_modules/.bin目录下,同时将./bin加入当环境变量$PATH中,所以如果在全局直接运行该命令会去全局目录里找,可能会找不到该命令就会报错。比如 npm run start,他是执行的webpack-dev-server带上参数
2、还有一种情况,就是单纯的执行脚本命令,比如 npm run build,实际运行的是 node build.js,即使用 node 执行 build.js 这个文件
9.babel原理和用途
babel 用途
- 转义 esnext、typescript 到目标环境支持 js (高级语言到到低级语言叫编译,高级语言到高级语言叫转译)
- 代码转换(taro)
- 代码分析(模块分析、tree-shaking、linter 等)
bebel 如何转换的?
对源码字符串 parse 生成 AST,然后对 AST 进行增删改,然后输出目标代码字符串
转换过程
- parse 阶段:首先使用
@babel/parser将源码转换成 AST - transform 阶段:接着使用
@babel/traverse遍历 AST,并调用 visitor 函数修改 AST,修改过程中通过@babel/types来创建、判断 AST 节点;使用@babel/template来批量创建 AST - generate 阶段:使用
@babel/generate将 AST 打印为目标代码字符串,期间遇到代码错误位置时会用到@babel/code-frame
TS
1. TypeScript 是什么
TypeScript,简称 ts,是微软开发的一种静态的编程语言,它是 JavaScript 的超集。 那么它有什么特别之处呢?
- 简单来说,js 有的 ts 都有,所有js 代码都可以在 ts 里面运行。
- ts 支持类型支持,ts = type +JavaScript。
2.TypeScript的类型
- ①、基础类型Boolean 、Number 、String 、Symbol
let isDone: boolean = false;
// ES5:var isDone = false;
let count: number = 10;
// ES5:var count = 10;
let name: string = "semliker";
// ES5:var name = 'semlinker';
const sym = Symbol();
let obj = {
[sym]: "semlinker",
};
console.log(obj[sym]); // semlinker
3 Array、Tuple (元组)
let list: number[] = [1, 2, 3];
// ES5:var list = [1,2,3];
let list: Array<number> = [1, 2, 3]; // Array<number>泛型语法
// ES5:var list = [1,2,3];
4 undefined 、 null
默认情况下 null 和 undefined 是所有类型的子类型。 就是说你可以把 null 和 undefined 赋值给 number 类型的变量。
let age: number = null
let realName: string = undefined
5 any、unknown 、never
any在 TypeScript 中,任何类型都可以被归为 any 类型。这让any类型成为了类型系统的顶级类型(也被称作全局超级类型)。但是不建议使用 any,不然就丧失了 TS 提供的保护机制,失去了使用TS的意义。
unknown所有类型也都可以赋值给 unknown。这使得 unknown 成为 TypeScript 类型系统的另一种顶级类型(另一种是 any)。它的定义和 any 定义很像,但是它是一个安全类型,使用 unknown 做任何事情都是不合法的。
nevernever类型表示的是那些永不存在的值的类型。
有些情况下值会永不存在,比如,
- 如果一个函数执行时抛出了异常,那么这个函数永远不存在返回值,因为抛出异常会直接中断程序运行。
- 函数中执行无限循环的代码,使得程序永远无法运行到函数返回值那一步。never 类型是任何类型的子类型,也可以赋值给任何类型。