Vue 面试题
1.Vue 双向绑定原理
2.描述下 vue 从初始化页面–修改数据–刷新页面 UI 的过程?
3.你是如何理解 Vue 的响应式系统的?
4.虚拟 DOM 实现原理
5.既然 Vue 通过数据劫持可以精准探测数据变化,为什么还需要虚拟 DOM 进行 diff 检测差异?
6.Vue 中 key 值的作用?
7.Vue 的生命周期
8.Vue 组件间通信有哪些方式?
9.watch、methods 和 computed 的区别?
10.vue 中怎么重置 data?
11.组件中写 name 选项有什么作用?
12.vue-router 有哪些钩子函数?
13.route 和 router 的区别是什么?
14.说一下 Vue 和 React 的认识,做一个简单的对比
15.Vue 的 nextTick 的原理是什么?
16.Vuex 有哪几种属性?
17.vue 首屏加载优化
18.Vue 3.0 有没有过了解?
19.vue-cli 替我们做了哪些工作?
…
算法
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
- 冒泡排序
- 选择排序
- 快速排序
- 二叉树查找: 最大值、最小值、固定值
- 二叉树遍历
- 二叉树的最大深度
- 给予链表中的任一节点,把它删除掉
- 链表倒叙
- 如何判断一个单链表有环
- 给定一个有序数组,找出两个数相加为一个目标数
…
由于篇幅限制小编,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!有需要的程序猿(媛)可以帮忙点赞+评论666
我们看下 Frames(帧) 这一栏,能看到红框中在一次输入中,776.9 ms 内都是 1 fps 的。这代表什么意思?我们知道正常网页刷新频率一般是 60 帧,也就是 16.67ms(1s/60)必须要刷新一次,否则就会有卡顿感,刷新时间越长,就越卡顿,在当前例子中,我们输入字符后,776.9 ms 后才触发更新,可以说是相当相当卡了。
我们知道 JS 是单线程的,也就是执行代码与绘制是同一个线程,必须等代码执行完,才能开始绘制。那具体是那一块代码执行时间长了呢?这里我们就要看 Main 这一栏,这一栏列出了 JS 调用栈。
在 Main 这一栏中,可以看到我们的 KeyPress 事件执行了 771.03ms,然后往上拖动,就能看到 KeyPress 中 JS 的执行栈,能找到每个函数的执行时间。
拖动到最下面,你可以看到 onChange 函数执行了很长时间,点击它,你可以在下面看到这个函数的具体信息,点击 demo1.js:7
甚至能看到每一行执行了多长时间。
罪魁祸首找到了,第九行代码执行了 630ms,找到问题所在,就好解决了。
这是一个最简单的例子,这种由单个地方引起的性能问题,也是比较好解决的。找到它、修改它、解决它!
React Profiler
React.Profiler 是 React 提供的,分析组件渲染次数、开始时间及耗时的一个 API,你可以在官网找到它的文档(https://zh-hans.reactjs.org/docs/profiler.html)。
当然我们不需要每个组件都去加一个 React.Profiler 包裹,在开发环境下,React 会默记录每个组件的信息,我们可以通过 Chrome Profiler Tab 整体分析。
当然我们的 Chrome 需要安装 React 扩展,才能在工具栏中找到 Profiler
的 Tab。
Profiler 的用法和 Performance 用法差不多,点击开始记录,操作页面,然后停止记录,就会产出相关数据。
我找了一张比较复杂的图来做个示例,图中的数字分别表示:本次操作 React 做了 26 次 commit,第 14 次 commit 耗时最长,该次 commit 从 3.4s 时开始,消耗了 89.1 ms。
同时我们切换到 Ranked 模式,可以看到该次 commit,每个组件的耗时排名。比如下图表示 MarkdownText
组件耗时最长,达到 13.7 ms。
通过 React.Profiler,我们可以清晰的看到 React 组件的执行次数及时间,为我们优化性能指明了方向。
但我们需要注意的是, React.Profiler 记录的是 commit 阶段的数据。React 的执行分为两个阶段:
-
render 阶段:该阶段会确定例如 DOM 之类的数据需要做哪些变化。在这个阶段,React 将会执行 render 及 render 之前的生命周期。
-
commit 阶段:该阶段 React 会提交更新,同时在这个阶段,React 会执行像
componentDidMount
和componentDidUpdate
之类的生命周期函数。
所以 React.Profiler 的分析范围是有限的,比如我们最开始的 input 示例,通过 React Profiler 是分析不出来性能问题的。
性能改进
如果所有的性能问题都像上面这么简单就好了。某个点耗时极长,找到它并改进之,皆大欢喜。但在 React 项目中,最容易出现的问题是组件太多,每个组件执行 1ms,一百个组件就执行了 100ms,怎么优化?没有任何一个突出的点可以攻克,我们也不可能把一百个组件都优化成 0.01 ms。
class App extend React.Component{
constructor(props){
super(props);
this.state={
count: 0
}
}
render(){
return (
<Button onClick={()=>{ this.setState({count: 1}) }}>click
)
}
}
就像上面这个组件一样,当我们点击 Button 更新 state 时,A/B/C/D 四个组件均会执行一次 render 计算,这些计算完全是无用的。当我们组件够多时,会逐渐成为性能瓶颈!我们目标是减少不必要的 render。
PureComponent/ShouldComponentUpdate
说到避免 Render,当然第一时间想到的就是 ShouldComponentUpdate 这个生命周期,该生命周期通过判断 props 及 state 是否变化来手动控制是否需要执行 render。当然如果使用 PureComponent,组件会自动处理 ShouldComponentUpdate。
使用 PureComponent/ShouldComponentUpdate 时,需要注意几点:
-
PureComponent 会对 props 与 state 做浅比较,所以一定要保证 props 与 state 中的数据是 immutable 的。
-
如果你的数据不是 immutable 的,或许你可以自己手动通过 ShouldComponentUpdate 来进行深比较。当然深比较的性能一般都不好,不到万不得已,最好不要这样搞。
React.memo
React.memo 与 PureComponent 一样,但它是为函数组件服务的。React.memo 会对 props 进行浅比较,如果一致,则不会再执行了。
const App = React.memo(()=>{
return
});
当然,如果你的数据不是 immutable 的,你可以通过 React.memo 的第二个参数来手动进行深比较,同样极其不推荐。
React.memo 对 props 的变化做了优化,避免了无用的 render。那 state 要怎么控制呢?
const [state, setState] = useState(0);
React 函数组件的 useState,其 setState 会自动做浅比较,也就是如果你在上面例子中调用了 setState(0)
,函数组件会忽略这次更新,并不会执行 render 的。一般在使用的时候要注意这一点,经常有同学掉进这个坑里面。
善用 React.useMemo
React.useMemo 是 React 内置 Hooks 之一,主要为了解决函数组件在频繁 render 时,无差别频繁触发无用的昂贵计算 ,一般会作为性能优化的手段之一。
const App = (props)=>{
const [boolean, setBoolean] = useState(false);
const [start, setStart] = useState(0);
// 这是一个非常耗时的计算
const result = computeExpensiveFunc(start);
}
在上面例子中, computeExpensiveFunc
是一个非常耗时的计算,但是当我们触发 setBoolean
时,组件会重新渲染, computeExpensiveFunc
会执行一次。这次执行是毫无意义的,因为 computeExpensiveFunc
的结果只与 start
有关系。
React.useMemo 就是为了解决这个问题诞生的,它可以指定只有当 start
变化时,才允许重新计算新的 result
。
const result = useMemo(()=>computeExpensiveFunc(start), [start]);
我建议 React.useMemo 要多用,能用就用,避免性能浪费。
合理使用 React.useCallback
在函数组件中,React.useCallback 也是性能优化的手段之一。
const OtherComponent = React.memo(()=>{
…
});
const App = (props)=>{
const [boolan, setBoolean] = useState(false);
const [value, setValue] = useState(0);
const onChange = (v)=>{
axios.post(/api?v=${v}&state=${state}
)
}
return (
{/* OtherComponent 是一个非常昂贵的组件 */}
)
}
在上面的例子中, OtherComponent
是一个非常昂贵的组件,我们要避免无用的 render。虽然 OtherComponent
已经用 React.memo 包裹起来了,但在父组件每次触发 setBoolean
时, OtherComponent
仍会频繁 render。
因为父级组件 onChange
函数在每一次 render 时,都是新生成的,导致子组件浅比较失效。通过 React.useCallback,我们可以让 onChange 只有在 state 变化时,才重新生成。
const onChange = React.useCallback((v)=>{
axios.post(/api?v=${v}&state=${state}
)
}, [state])
通过 useCallback 包裹后, boolean
的变化不会触发 OtherComponent
,只有 state
变化时,才会触发,可以避免很多无用的 OtherComponent
执行。
但是仔细想想, state
变化其实也是没有必要触发 OtherComponent
的,我们只要保证 onChange
一定能访问到最新的 state
,就可以避免 state
变化时,触发 OtherComponent
的 render。
总结
根据路线图上的重点去进行有针对性的学习,在学习过程中,学会写笔记,做总结。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
这里分享一些前端学习笔记:
-
html5 / css3 学习笔记
-
JavaScript 学习笔记
-
Vue 学习笔记
根据路线图上的重点去进行有针对性的学习,在学习过程中,学会写笔记,做总结。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
这里分享一些前端学习笔记:
-
html5 / css3 学习笔记
-
JavaScript 学习笔记
-
Vue 学习笔记