Object.defineProperty来劫持整个对象,然后进行深度遍历,给每个属性添加 getter 和 setter,实现响应式,但是存在以下问题:
-
初始化时需要遍历对象所有key,层级多的情况下,性能有一定影响
-
动态新增、删除对象属性无法拦截,只能用set/delete api代替
-
不支持新的Map、Set等数据结构
-
无法监控到数组下标的变化(监听的性能代价太大) proxy的优势:
-
可以监听多种操作方法,包括动态新增的属性和删除属性、has、apply等操作
-
可以监听数组的索引和 length 等属性
-
懒执行,不需要初始化的时候递归遍历
-
浏览器新标准,性能更好,并且有持续优化的可能
使用vue渲染大量数据时应该怎么优化?说下你的思路!
-
可以采取分页的方式获取,避免渲染大量数据
-
[vue-virtual-scroller (opens new window) ]等虚拟滚动方案,只渲染视口范围内的数据
-
如果不需要更新,可以使用v-once方式只渲染一次
-
通过[v-memo (opens new window) ]可以缓存结果,结合
v-for使用,避免数据变化时不必要的VNode创建 -
可以采用懒加载方式,在用户需要的时候再加载数据,比如
tree组件子树的懒加载
- 还是要看具体需求,首先从设计上避免大数据获取和渲染;实在需要这样做可以采用虚表的方式优化渲染;最后优化更新,如果不需要更新可以
v-once处理,需要更新可以v-memo进一步优化大数据更新性能。其他可以采用的是交互方式优化,无线滚动、懒加载等方案
Proxy只会代理对象的第一层,那么Vue3又是怎样处理这个问题的呢?
判断当前Reflect.get的返回值是否为Object,如果是则再通过reactive方法做代理, 这样就实现了深度观测。
监测数组的时候可能触发多次get/set,那么如何防止触发多次呢?
我们可以判断key是否为当前被代理对象target自身属性,也可以判断旧值与新值是否相等,只有满足以上两个条件之一时,才有可能执行trigger。
接口请求一般放在哪个生命周期中?
接口请求一般放在mounted中,但需要注意的是服务端渲染时不支持mounted,需要放到created中。
SSR了解
SSR有着更好的SEO、并且首屏加载速度更快等优点。不过它也有一些缺点,比如我们的开发条件会受到限制,服务器端渲染只支持beforeCreate和created两个钩子,当我们需要一些外部扩展库时需要特殊处理,服务端渲染应用程序也需要处于Node.js的运行环境。还有就是服务器会有更大的负载需求。
vue的编译流程
-
parse解析阶段:使用正则对
template模板进行解析,将标签、指令、属性等转化为AST抽象语法树 -
optimize优化阶段:遍历AST,对静态节点进行标记和提升,优化runtime的性能
-
generate生成阶段:将AST转化为render函数字符串