面试整理之原理问题
最近面试问到的原理问题还是挺多的,大致整理下
关于vue的
1.MVVM双向数据绑定原理
所谓MVVM数据双向绑定,即主要是:数据变化更新视图,视图变化更新数据。
视图变化更新数据我们可以通过事件监听的方式来实现,关键点在于数据变化如何更新视图.Vue内部通过Object.defineProperty
方法属性拦截的方式,把data
对象里每个数据的读写转化成getter
/setter
,当数据变化时通知视图更新。
实现方法: 首先使用Object.defineProperty
方法使data中的数据变化变成可监测, 然后在数据被读或写的时候通知那些依赖该数据的视图更新了,为了方便,我们需要先将所有依赖收集起来,一旦数据发生变化,就统一通知更新。其实,这就是典型的“发布订阅者”模式,数据变化为“发布者”,依赖对象为“订阅者”。
创建一个依赖收集容器,也就是消息订阅器Dep,用来容纳所有的“订阅者”。订阅器Dep主要负责收集订阅者,然后当数据变化的时候后执行对应订阅者的更新函数。
2.vuex实现原理
vuex 整体思想诞生于 flux,可其的实现方式完完全全的使用了 vue 自身的响应式设计,依赖监听、依赖收集都属于 vue 对对象 Property set get 方法的代理劫持。最后一句话结束 vuex 工作原理,vuex 中的 store 本质就是没有 template 的隐藏着的 vue 组件;
解析:vuex的原理其实非常简单,它为什么能实现所有的组件共享同一份数据? 因为vuex生成了一个store实例,并且把这个实例挂在了所有的组件上,所有的组件引用的都是同一个store实例。 store实例上有数据,有方法,方法改变的都是store实例上的数据。由于其他组件引用的是同样的实例,所以一个组件改变了store上的数据, 导致另一个组件上的数据也会改变,就像是一个对象的引用。
3.vue-router实现原理
其他
4.promise理解
Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理
有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
优点: 可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise
对象提供统一的接口,使得控制异步操作更加容易。
缺点: 无法取消Promise
,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise
内部抛出的错误,不会反应到外部。第三,当处于pending
状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
API: Promise.prototype.then(): 为 Promise 实例添加状态改变时的回调函数。then
方法的第一个参数是resolved
状态的回调函数,第二个参数(可选)是rejected
状态的回调函数。可以使用链式写法,
Promise.prototype.catch(): 是.then(null, rejection)
或.then(undefined, rejection)
的别名,用于指定发生错误时的回调函数。
Promise.prototype.finally(): 用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
Promise.all(): 用于将多个 Promise 实例,包装成一个新的 Promise 实例,参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。
Promise.race():
Promise.any(): 方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只要参数实例有一个变成fulfilled
状态,包装实例就会变成fulfilled
状态
Promise.resove(): 将现有对象转为 Promise 对象
Promise.reject(): Promise.reject(reason)
方法也会返回一个新的 Promise 实例,该实例的状态为rejected
。
promise与settimeout执行顺序: then和settimeout执行顺序,即setTimeout(fn, 0)
在下一轮“事件循环”开始时执行,Promise.then()
在本轮“事件循环”结束时执行。因此then 函数先输出,settimeout后输出。
5.webpack理解
6.babel实现
7.JS作用域理解
8.JS原型链
9.JS继承
10.前端性能优化
页面加载缓慢原因:
网络层面: 1.过多的HTTP请求 2.资源访问宽带小 3.网页元素(图片,视频,样式)太大
浏览器渲染层面: 1.渲染阻塞 JS阻塞与CSS阻塞 2.重复渲染 3.DNS解析
服务端层面: 1.硬件配置低 2.服务器软件, 比如防火墙,内网策略等 3.未对NGINX这类web服务器进行配置优化 4.CPU占满,数据库未优化 5.包含了过多的分析工具
代码部分: 1.未对代码进行打包,压缩,兼容性优化 2.未合并重复的请求,代码 3.没有良好的编码习惯 4.未加入async异步机制 5.未考虑页面加载,用户体验
页面优化处理:
1.减少HTTP请求, 合并请求,图片资源合并
2.使用内容分发网络CDN 是用于分发传送内容的负载的服务器网络.从本质上讲,您网站的副本存储在多个地理位置不同的数据中心,以使用户可以更快,更可靠的 访问您的网络.除了购买一些CDN服务商的服务外,可以使用公共CDN网络上的资源
3.避免空src和空href标签
4.减少浏览器的重排reflow和重绘repaint, 使用vue减少操作DOM,减少不必要的DOM层级,使用class设计元素属性,不使用style设计属性
5.CSS放在顶部,JS放在底部
6.减少DNS查找,使用DNS预解析(NDS缓存)
7.压缩资源 主要工具 webpack gulp
8.避免3xx重定向,写完整请求路径,4xx请求错误 ,使用工具检查,使用路由规则
9.尽量使用get请求,使用请求缓存
10.去除不必要的cookie,压缩cookie大小,设置合适的过期时间
11.使用浏览器缓存,localstorage sessionstorage
12.缩短服务器响应时间
13.使用优化工具: Google Page Speed
JsPerf&Benchmark.js
11.浏览器输入URL到页面渲染的过程
1. 用户输入URL地址
2.浏览器解析URL 主机名
3. 浏览器将主机名转换成服务器ip地址(浏览器先查找本地DNS缓存列表,没有的话再向浏览器默认的DNS服务器发送查询请求 同时缓存)
4. 浏览器将端口号从URL中解析出来
5. 浏览器建立一条鱼目标web服务器的TCP连接(三次握手)
6. 浏览器向服务器发送一条HTTP请求报文
7. 服务器向浏览器返回一条HTTP响应报文
8. 关闭连接 浏览器解析文档
9. 如果文档中有资源 重复6 7 8动作, 直至资源全部加载完毕
简洁版: 1.域名解析 --> 2.发起 TCP 的 3 次握手 --> 3.建立 TCP 连接后发起 http 请求 --> 4.服务器响应 http 请求,浏览器得到 html 代码 --> 5.浏览器解析 html 代码,并请求 html 代码中的资源(如 js、css、图片等) --> 6.浏览器对页面进行渲染呈现给用户
12.TCP三次握手
CP 协议是面向连接的通信协议,即在传输数据前先在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。
在 TCP 连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”
第一次握手,客户端向服务器端发送一个带 SYN 标志的数据包,等待服务器确认
第二次握手,服务器端向客户端回传一个带有 SYN/ACK 标志的数据包,通知客户端收到了连接请求
第三次握手,客户端再次向服务器端回传一个带 ACK 标志的数据包,确认连接,“握手”结束。
12.2 TCP四次挥手
1、客户端向服务器发送一个断开连接的请求(不早了,我该走了);
2、服务器接到请求后发送确认收到请求的信号(知道了);
3、服务器向客户端发送断开通知(我也该走了);
4、客户端接到断开通知后断开连接并反馈一个确认信号(嗯,好的),服务器收到确认信号后断开连接;
解析:
第一次挥手:主动关闭方发送一个 FIN,用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方:我已经不会再给你发数据了(当然,在 fin 包之前发送出去的数据,如果没有收到对应的 ack 确认报文,主动关闭方依然会重发这些数据),但是,此时主动关闭方还可 以接受数据。
第二次挥手:被动关闭方收到 FIN 包后,发送一个 ACK 给对方,确认序号为收到序号+1(与 SYN 相同,一个 FIN 占用一个序号)。
第三次挥手:被动关闭方发送一个 FIN,用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会再给你发数据了。
第四次挥手:主动关闭方收到 FIN 后,发送一个 ACK 给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手。
13.跨域问题解决
1.CORS 在vue项目中前端不需要做什么处理,后端设置Access-Control-Allow-Origin请求头
2.chrome浏览器支持可跨域的设置,根据网上的配置方法配置
3.vue.config.js文件中配置代理
module.exports = { devServer: { proxy: { '/api': { target: '<url>', // 跨域的地址 ws: true, changeOrigin: true, pathRewrite: {'^/api': '/'} } } } }
14.浏览器缓存策略
浏览器的缓存规则是在 http 协议头和 html 页面的 meta 标签中定义的。主要分为两部分:强缓存和协商缓存。
强缓存是指缓存的副本在有效期内,浏览器直接获取这个副本并渲染。
强缓存主要涉及的 http 协议报头有:Expires,cache-control。
<meta http-equiv="Cache-Control" content="max-age=7200" /> // content: no-cache||no-store||max-age <meta http-equiv="Expires" content="Mon, 20 Jul 2013 23:00:00 GMT" /> // 过期时间
协商缓存是在强缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程。
协商缓存的过程:浏览器发起 http 请求,浏览器缓存返回缓存标识(请求的缓存结果失效),浏览器携带该资源的缓存标识,向服务器发起 http 请求,如果服务器返回 304 和 not modified,浏览器向浏览器缓存获取该请求的缓存结果,浏览器环迅返回该请求结果。如果服务器返回 200 和请求结果(该资源更新了,重新返回请求结果),浏览器将该请求结果和缓存标识存入浏览器缓存中。
协商缓存主要涉及的 http 协议报头有:Last-Modified 和 ETag。
15.前端工程化
1.前端工程化概念: 前端项目越来越大,引用资源越来越多.为了提高效率和降低成本,即提高开发过程中的开发效率,减少不必要的重复工作时间,前端工程化变得越来越必要
2.前端工程化主要从四个方面进行: 前端模块化,前端组件化,前端规范化,前端自动化
前端模块化: 模块化就是将一个大文件拆分成相互依赖的小文件,再进行统一的拼装和加载.JS,CSS,引入资源的模块化
主要使用打包工具:webpack,parcel,rollup
前端组件化: 组件是从UI拆分下来的每个包含模板(HTML)+样式(CSS)+逻辑(JS)功能完备的结构单元
使用组件可以使项目开发更高效灵活
主要组件化框架: vue,react,angular 微信小程序
前端规范化: 规范化其实是工程化中很重要的一个部分,项目初期规范制定的好坏会直接影响到后期的开发质量。
主要规范: 编码规范 eslint stylelint, 接口规范, Git开发规范, 命名规范, 组件管理
前端自动化: 任何简单重复的工作都应该使用自动化工具来完成
主要自动化: 自动构建项目 gulp;
自动化测试: 使用asset和chai进行单元测试; 使用Istanbul进行覆盖率测试; 使用benchmark进行性能测试; 使用jest进行UI测试
自动部署项目 pm2
16.提高首屏加载速度
- 使用CDN资源,减小服务器带宽压力
- 路由懒加载
- 将一些静态js css放到其他地方(如OSS),减小服务器压力
- 按需加载三方资源,如iview,建议按需引入iview中的组件
- 使用nginx开启gzip减小网络传输的流量大小
- 若首屏为登录页,可以做成多入口,登录页单独分离为一个入口
- 使用uglifyjs-webpack-plugin插件代替webpack自带UglifyJsPlugin插件