金三银四的季节又来了,笔者一直在武汉工作,年前裸辞后,过完年一共面了接近两个星期,有阿里,腾讯,金山,万科,趣头条等公司,在武汉拿到了4个offer(金山、万科、航班管家、财人汇)后,又在深圳一站式面了腾讯,最终选择了腾讯,这里不完全记录一点面试中遇到的问题
面试不完全汇总
float和flex的区别
为什么会有flex
了解CI CD吗
React和Vue的差异
移动端高清问题
移动端点击穿透问题
Nodejs的模块化和ES6的模块化区别
http的优缺点
restful和graphQL优缺点,对比
事件委托的优缺点
何时需要用到border-box
csrf是什么,如何用预防
fastclik的作用
前端性能优化
CSS居中+等比宽高问题
margin-top/margin-bottom百分数问题
TCP和UDP区别
float和flex的区别
float
脱离文档流
布局的传统解决方案,基于盒状模型,依赖 display 属性 + position属性 + float属性。它对于那些特殊布局非常不方便,比如,垂直居中就不容易实现。
缺点:
– 容错性差,耦合度高,其中一个浮动元素出现问题,其他也会受影响
– 必须要有固定的布局
– 低版本IE不兼容
flex
W3C 提出了一种新的方案—-Flex 布局,可以简便、完整、响应式地实现各种页面布局
flex性能改进在于,
– 相比传统margin,可伸缩性强(不算性能)
– 相比float,关联性重绘好很多
– 相比tranform,子元素和父元素样式控制操作更少
RESTful优缺点
特点:充分利用 HTTP 协议本身语义。
无状态,这点非常重要。在调用一个接口(访问、操作资源)的时候,可以不用考虑上下文,不用考虑当前状态,极大的降低了复杂度。
HTTP 本身提供了丰富的内容协商手段,无论是缓存,还是资源修改的乐观并发控制,都可以以业务无关的中间件来实现。
React和Vue的差异
相似处
Virtual DOM、组件化、Props
差异
1. 渲染优化,是否需要用shouldComponentUpdate,PureComponent
2. JSX 和 Template , CSS in JS
3. Vue-cli 和 create-react-app
4. 学习难度,学 React 前,你需要知道 JSX 和 ES2015
移动端高清问题
- DPR (device pixel ratio)= device pixel(设备像素) \ CSS pixel(css像素)
- 1px解决方案
> – border-image 、 background-image 缺点:修改颜色麻烦,圆角需要特殊处理
> – box-shadow 缺点:在Safari下不支持小数设置
> – 伪类 + transform
> – SVG
> – viewport + rem
移动端点击穿透问题
场景:上层元素A绑定了tap事件,下层元素B绑定了click事件。当我们点击A时,A元素隐藏,此时也会触发下层B元素的click事件。
原因就是当上层A的tap事件发生后,其实是touchend结束后,会触发click事件,因为这几个事件的触发顺序是touchstart-touchmove-touchend-click。因此当click事件触发300ms后,上面的A元素已经消失,此时真正点击的就相当于下层的B元素,因此会发生点击穿透事件。
解决方案
– 都使用click或者tap
– 在click事件触发前阻止,在touchend事件中使用e.preventDefault()
– 使用fast-click。fastclick是一个专门解决300ms点击延迟的库。
FastClick实现原理
在document.body绑定touchstart和touchend事件
touchstart
用于记录当前点击的元素的targetElement
touchend
– 阻止默认事件(屏蔽之后的click事件)
– 合成click事件,并添加可跟踪属性forwardedTouchEvent
– 在targetElement上触发click事件
– targetElement上绑定的事件立即执行,完成FastClick
CommonJS的模块化和ES6的模块化区别
CommonJS主要依赖module、exports、require、global这几个环境变量。
CommonJS用同步方式加载模块。
ES6 module的模块不是对象,import
命令会被JS引擎动态分析,在编译时就引入模块代码,而不是在代码运行时加载,所以无法实现条件加载。(ps: 也正是因为这个,使得静态分析成为可能)
差异
1. CommonJS模块输出的是一个值的拷贝,ES6模块输出的是值的引用
– CommonJS模块输出值的拷贝,一旦输出一个值,模块内部的变化就影响不到这个值。
– ES6模块的运行机制与CommonJS不一样。JS引擎对脚本静态分析的时候,遇到模块加载命令import
,就会生产一个只读引用。等到脚本真正执行时,再根据只读引用,到被加载的模块中取值。原始值变了,import
加载的值也会跟着变。因此ES6模块是动态引用,并且不会缓存值,模块里的变量绑定其所在的模块。
2. CommonJS模块是运行时加载,ES6模块是编译时输出接口
– 运行时加载:CommonJS模块就是对象,即在输入时先加载整个模块,生产一个对象,然后再从这个对象上面读取方法,这种加载成为”运行时加载“
– 编译时加载:ES6模块不是对象,而是通过export
命令显示指定输出的代码,import
时采用静态命令的形式。即在import
时可以指定加载某个输出值,而不是加载整个模块,这种加载成为编译时加载
CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
RESTful优缺点
优点:
1. 轻量,直接基于http,不需要任何别的消息协议。get/post/put/delete为CURD操作
2. 面向资源,一目了然,具有自解释性
3. 数据描述简单,一般是xml,json做数据交换
缺点:
一个适用于简单操作的接口规范,复杂操作并不适用,适合CRUD并且只适合CRUD,有的浏览器可能不支持POST、GET以外的操作,要特殊处理。
ps: 多个接口,更新订单收款状态、更新订单支付状态、更新订单结算状态。批量操作,get超出长度
- 客户端-服务器:提供服务的服务器和使用服务的客户端分离解耦
- 提高客户端的便捷性(操作简单)
- 简化服务器提高可伸缩性(高性能、低成本)
- 允许客户端服务端分组优化不受影响
- 无状态:来自客户的每一个请求必须包含服务器处理该请求所需的所有信息(请求信息唯一性)
- 提高了可见性(可以考虑每个请求)
- 提高了可靠性(更容易故障恢复)
- 提高了可扩展性(降低了服务器资源使用)
- 可缓存:服务器必须让客户端知道请求是否可以被缓存?如果可以,客户端可以重用之前的请求信息发送请求
- 减少交互连接数
- 减少链接过程的网络延迟
- 分层系统:允许服务器和客户端之前的中间层(代理,网关等)代替服务器对客户端的请求进行回应,而客户端不需要关心与它交互的组件之外的事情
- 提高了系统的可扩展性
- 简化了系统的复杂性
- 统一接口:客户和服务器之前通信的方法必须是统一的。
提高交互的可见性
鼓励单独优化改善组件 - 支持按需代码:服务器可以提供一些代码或者脚本并在客户的运行环境中执行
- 提高了可扩展性
事件委托的优缺点
优点:
1. 节省内存,减少事件注册。
2. 适合动态内容
确定:
1. 如果把所有事件都是用事件代理,可能会出现误判。即本不该被触发的事件被绑定上了事件。
2. 基于冒泡,对于不冒泡的事件不支持。
3. 层次过多时,可能会被某曾组织掉。
CSRF
特点
– CSRF通常发生在第三方域名
– CSRF攻击者不能获取到Cookie等信息,只是使用。
防御策略
– 阻止不明外域的访问
– 同源监测
– Samesite cookie
- 提交时要求附加本域下才能获取的信息
- CSRF TOken
- 双重Cookie验证
- 提交验证码
为什么用transform居中而不是marginLeft/Top
浏览器渲染过程
解析DOM Tree,创建一个或多个渲染层(layer)
将每个层独立的绘进位图中(计算样式->布局->栅格化)
将层作为纹理(texture)上传至GPU
复合(composite)多个层来生成最终的屏幕图像
每个层的样式出现调整后,要重新计算样式->重新布局->重新栅格化->重新组合
使用top/left只会创建一个层,而是用transform会使浏览器将元素单独提取放在GPU单独的渲染层中,这样有三点好处:
1. 该元素任何合成属性(Composite Property)的变化将不会影响原有文档,不会导致文档被重新布局(重绘、回流)
2. 该层将由GPU负责渲染,从而节省CPU资源,不会阻塞主线程JS代码的执行
3. 动画更为平顺,这是因为使用transform可以小于像素的单位进行绘制
可能带来的负作用是额外的渲染层导致更多的线程间通信,如果过度使用,导致生成成百上千的渲染层,那反而会导致组合各层图像的成本迅速上升成为主要矛盾,且我们需要记住GPU也是有内存限制的。
使用css设置rem
使用calc(100vw / 屏幕宽度)
javascript
[] == ![] 这个要牵涉到 JavaScript 中不同类型 == 比较的规则, 具体是由相关标准定义的. ![] 的值是 false, 此时表达式变为 [] == false, 参照标准, 该比较变成了 [] == ToNumber(false), 即 [] == 0. 这个时候又变成了 ToPrimitive([]) == 0, 即 '' == 0, 接下来就是比较 ToNumber('') == 0, 也就是 0 == 0, 最终结果为 true.
### CSS居中 + 宽高等比变化
- font-size em-square
- line-height 实际占地高度
- 100px 100px -> 103px
- vertical top middle bottom text-top text-bottom
- 图片下面有空隙
- vertical-align top
- img{display: block}
- font-size 0 傻逼才用
- inline-block 元素对不齐 无解 用 flex或float
- inline-block 有空隙 用 flex 或 float
css垂直居中对齐
<main>
<span>Center me, please!</span>
</main>
1. display: flex + margin: auto
main{
width: 100%;
min-height: 152px;
display: flex;
}
main > span {
margin: auto;
}
- display: flex , grid
main{
width: 100%;
min-height: 152px;
display: grid;
justify-content: center;
align-items: center;
}
main > span {
background: #b4a078;
color: white;
padding: .3em 1em .5em;
border-radius: 3px;
box-shadow: 0 0 .5em #b4a078;
}
```
3. position: absolute + calc()
```css
main{
width: 100%;
min-height: 152px;
display: flex;
}
main > span {
position: absolute;
top: calc(50% - 16px);
left: calc(50% - 72px);
}
```
4. position: absolute + translate
```css
main{
width: 100%;
min-height: 152px;
display: flex;
}
main > span {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
}
```
5. display: table / table-cell + vertical-align: middle
```css
main {
width: 100%;
height: 152px;
display: table;
}
main > div {
display: table-cell;
text-align: center;
vertical-align: middle;
}
- 伪元素 :after + vertical-align: middle
main {
width: 100%;
height: 152px;
text-align: center;
}
main::after {
content:'';
display: inline-block;
height: 100%;
vertical-align: middle;
}
宽高等比用css如何实现
- 使用隐藏图片
完美兼容PC端、移动端
如果div容器不给高度,它的高度会随容器内部元素的变化而撑大
在容器内添加一张等比宽高的图片,给图片设置宽度100% 高度auto
<style>
#container {
width: 100%;
}
.attr {
background-color: #008b57;
}
.attr img{
width: 100%;
height: auto;
}
</style>
<div id='container'>
<div class='attr'>
<img src="1.png" alt="">
</div>
</div>
还可以用base64优化
- 使用vmin
将父容器的宽度和高度定义为相同vmin,这样父容器宽高就是相同值,然后给子容器宽高设置百分比
– vw 相对于视窗的宽度
– vh 相对于视窗的高度
– vmin 相对于视口的宽度或高度中较小的那个被均分为100单位的vmin
– vmax 相对于视口的宽度或高度中较大的那个被均分为100单位的vmax
#container{
width: 100vmin;
height: 100vmin;
}
.attr {
width: 50%;
height: 50%;
background-color: orange;
}
- 使用scale
.attr{
width:50%;
height: calc(50%);
}
- padding-top/padding-bottom 实现
因为padding-bottom的属性值百分比是按照父容器的宽度来计算。
<style type="text/css">
#container {
width: 80%;
height: 500px;
}
.attr {
width: 50%;
height: 0;
padding-bottom: 50%;
background-color: #008b57;
}
</style>
<div id='container'>
<div class='attr'></div>
</div>
为什么margin-top/margin-bottom的百分数也是相对于width而不是height呢?
CSS权威指南中的解释:
我们认为,正常流中的大多数元素都会足够高以包含其后代元素(包括外边距),如果一个元素的上下外边距时父元素的height的百分数,就可能导致一个无限循环,父元素的height会增加,以适应后代元素上下外边距的增加,而相应的,上下外边距因为父元素height的增加也会增加,如果循环。
###UDP和TCP
UDP
简介:UDP是面向无连接的,UDP只是数据报文的搬运工,不保证有序且不丢失的传递,UDP协议没有控制流量算法,相比TCP更加轻量
面向无连接
UDP不需要和TCP一样在发送数据前进行三次握手建立连接。
并且只是数据报文的搬运工,不会对数据报文进行任何拆分和拼接。
具体来说:
– 在发送端,应用层的数据 -> 传输层UDP协议,UDP只会给数据增加一个UDP头标识
– 在接收端,网络层将数据传给传输层,UDP也只去除IP报文头,就传给应用层
不可靠性
首先不可靠性体现在无连接上,通信都不需要建立连接,想发就发,这样的情况肯定不可靠。
网络不佳的情况下,UDP因为没有拥塞控制,一直会以恒定的速度发送数据。弊端就是网络不好会丢包,优点就是在某些时效性要求高的场景适合。
高效
UDP的头部开销小,只有八个字节(TCP至少二十字节)
UDP头部包含以下几个数据:
– 两个十六位端口号,分别为源端口和目标端口
– 整个数据报文的长度
– 整个数据报文的检验
传输方式
UDP支持一对一,一对多,多对多,多对一,也就是单播,多播,广播
适用场景
- 直播
- 游戏
TCP
建立和断开连接都要进行握手。在传输过程中,通过各种算法保证数据的可靠性。
相对UDP来说不那么的高效。
头部
- Sequence number,这个序号保证了TCP传输的报文是有序的,对端可以通过序号顺序拼接报文
- Acknowledgement number,这个序号表示数据接收端 期望接受的下一个字节的编号是多少,同时也表示上一个序号的数据已经收到
- Window Size,窗口大小,表示还能接受多少字节的数据,用于流量控制
- 标识符
状态机
- 建立连接三次握手
不管是客户端还是服务端,TCP 连接建立完后都能发送和接收数据,所以 TCP 是一个全双工的协议。
第一次握手
客户端向服务端发送连接请求报文段。该报文段中包含自身的数据通讯初始序号。请求发送后,客户端便进入 SYN-SENT 状态。
第二次握手
服务端收到连接请求报文段后,如果同意连接,则会发送一个应答,该应答中也会包含自身的数据通讯初始序列号,发送完成后便进入SYN-RECEIVED状态。
第三次握手
当客户端收到连接同意的应答后,还要向服务端发送一个确认报文。
客户端发完这个报文段便进入ESTABLISHED状态。
服务端发完这个应答后也会进入ESTABLISHED状态。
ps: 为什么 TCP 建立连接需要三次握手,明明两次就可以建立起连接
因为这是为了防止出现失效的连接请求报文段被服务端接收的情况,从而产生错误。
断开连接四次握手
- 第一次握手
若客户端 A 认为数据发送完成,则它需要向服务端 B 发送连接释放请求。 - 第二次握手
B 收到连接释放请求后,会告诉应用层要释放 TCP 链接。然后会发送 ACK 包,并进入 CLOSE_WAIT 状态,此时表明 A 到 B 的连接已经释放,不再接收 A 发的数据了。但是因为 TCP 连接是双向的,所以 B 仍旧可以发送数据给 A。 - 第三次握手
B 如果此时还有没发完的数据会继续发送,完毕后会向 A 发送连接释放请求,然后 B 便进入 LAST-ACK 状态。 - 第四次握手
A 收到释放请求后,向 B 发送确认应答,此时 A 进入 TIME-WAIT 状态。该状态会持续 2MSL(最大段生存期,指报文段在网络中生存的时间,超时会被抛弃) 时间,若该时间段内没有 B 的重发请求的话,就进入 CLOSED 状态。当 B 收到确认应答后,也便进入 CLOSED 状态。
ps: 2MSL 为了保证 B 能收到 A 的确认应答。若 A 发完确认应答后直接进入 CLOSED 状态,如果确认应答因为网络问题一直没有到达,那么会造成 B 不能正常关闭。
ARQ协议
ARQ协议就是超时重传机制。通过确认和超时机制保证数据的正确送达。
ARQ协议包含停止等待ARQ和连续ARQ两种协议。
看完两件小事
如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:
- 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
- 关注公众号 「画漫画的程序员」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程
本文著作权归作者所有,如若转载,请注明出处
转载请注明:文章转载自「 Js中文网 · 前端进阶资源教程 」https://www.javascriptc.com