打开全栈工匠技能包-1小时轻松掌握SSR
两小时精通jq+bs插件开发
生产环境下如歌部署Node.js
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
网易内部VUE自定义插件库NPM集成
谁说前端不用懂安全,XSS跨站脚本的危害
webpack的loader到底是什么样的?两小时带你写一个自己loader
响应式系统的调度
期望有能力决定副作用函数的执行时机、次数及方式;
计算属性Computed
原理上是一个懒执行的副作用函数,在读取时重新计算其真正的值
watch 原理
利用副作用函数重新执行时的可调度性,当依赖的响应式数据发生变化时,执行effect的调度器函数,即回调;此外,一个立即执行的watch函数通过添加immediate选项来实现,通过flush选项指定回调函数的执行时机,本质上是利用了调用器和异步的微任务队列;
竞态问题
带入场景简单理解就是,watch的回调,存在异步,第二次更新覆盖第一次的回调执行内容;
非原始值的响应式方案
vue.js 3的响应式数据是基于Proxy 实现的,所以有必要理解Proxy及Reflect;
- Proxy对象可以创建一个代理对象,从而实现对其他对象的代理,代理指的是对一个对象基本语义的代理,允许我们拦截并重新定义对一个对象的基本操作,其中基本语义可以理解为对一个对象的读取和设置操作;
- Reflect对象具有和Proxy同样的方法,其特别之处在于可以接受第三个参数,receiver,即接收者,可以理解为函数调用过程中的this;
响应式的实现不只是简单的拦截get/set内部方法,更有迭代对象的拦截,例如for…in,for…of,set,map,这些具有特征的对象,都需要特别处理;
javaScript 对象
有俩种对象,一种为常规对象,另一种叫异质对象,其区别在于内部的实现方法;
原始值的响应式方案
原始值指的是Boolean、Number、BigInt、String、Symbol、undefined、null等类型,在js中原始值是按值传递的而非引用传递;
ref
ref实质上是一个包裹对象,由于Proxy无法提供对原始值的代理,所以用一层对象包裹,间接实现响应式,这也就是为什么在使用中需要.value;
toRef,toRefs
ref不仅可以用于原始值响应式方案,也能用来解决响应式丢失,这也就是toRef及toRefs出现的理由,toRef是代理一个对象的响应式值,toRefs则是多个,本质上是对响应式数据作的包装,或者叫访问代理,我们知道一般的响应式对象如reactive包裹的对象通过解构后会丢失响应式,那么可以在解构的时候通过toRef函数进行一次代理访问来保持响应式特性。
渲染器
用来执行渲染任务,是渲染真实DOM和跨平台能力的关键,渲染器把虚拟dom渲染为真实dom的过程叫作挂载,通常用英文mount表达。
渲染器与响应式系统
利用响应式系统的能力,可以做到数据编号自动更新页面,渲染器会执行挂载和打补丁操作,对于新内容,会执行挂载,而就内容,会执行打补丁操作,只更新新的node;
自定义渲染器
在浏览器平台,渲染器可以利用DOM API完成DOM操作,为了不直接依赖浏览器,将这些操作封装为可配置的对象,用户可以在调用createRenderer函数创建渲染器的时候自定义配置对象,从而实现自定义的行为;
挂载与更新
在这里我学到了HTML的节点的属性比想象中复杂,其中有俩个重要概念,HTML Attributes 和DOM Properties 并不完全对应,有的属性甚至是只读的,所以vue在属性的挂载上做了足够的工作; vue.js对特殊属性也做了属性增强,例如 class, style ,它们支持 字符,对象,数组 三种数据的格式;
简单Diff 算法
为了减少新旧node节点性能开销,完成更新操作,这个比较的算法就是diff算法,渲染器的核心就是diff算法,试图最大程度的复用DOM元素;简单diff算法的核心逻辑是,拿新的一组子节点中的节点去旧的一组子节点中寻找可复用节点。这个过程中key的作用就像是身份证号,在更新时通过key找到可复用的节点,避免过多的对DOM元素进行销毁和重建。
双端Diff 算法
指的是在新旧俩组子节点的四个端点之间分别进行比较,并试图找到可复用的节点,优势在于执行的DOM移动操作次数更少。
快速Diff算法
在实测中性能最优,借鉴了文本Diff中的预处理思路,先处理新旧俩组节点中相同的前置节点和相同的后置节点,当全部节点处理完毕后,如果无法简单的操作不存在的节点完成更新,会根据节点的索引关系,构造出一个最长递增子序列,其中最长递增子序列指向的节点则是不需要移动的节点。例如[2,8,9,0,3,5,7] 中 最长递增子序列为[0,3,5,7],这一部分对应的索引节点,就可以不去移动,从而提升diff性能;
组件化
组件化的能力可以使一个大模板变成一个个小模板,从而使组件可以组合,组成完整的页面,其核心也需要渲染器支持;
描述组件
利用虚拟节点的vnode.type属性来存储对象,渲染器根据虚拟节点的该属性类型来判断它是否是组件。
setup函数
该函数为了组合式API而生,要避免其与vue.js 2 中的传统组件选项混合使用,setup函数的返回值可以是俩种类型,如果是返回函数,则该函数作为组件的渲染函数;如果返回数据对象,则将该对象暴露在渲染上下文中。
异步组件
异步组件的实现并不复杂,用户也可以利用promise来自行实现,但是一个完善的异步组件仍然需要考虑很多问题如:
- 允许用户指定加载出错时要渲染的组件
- 允许用户指定Loading组件,以及展示该组件的延迟时间
- 允许用户设置加载组件的超时时长
- 组件加载失败时,为用户提供重试的能力
因此vue.js 3 提供了defineAsyncComponent函数,用来自定义异步组件;
内建组件和模块
KeepAlive、Teleport、Transition 组件,共同特点是与渲染器结合紧密,需要框架提供底层的实现与支持;
KeepAlive组件的作用类似于HTTP中的持久连接,可以避免组件不断的被销毁和重建造成的性能开销;实现核心是将组件放入一个隐藏容器中,从而使得可以维持当前状态,当被挂载时,将它从隐藏容器搬到原容器中。
Teleport组件可以完成跨越层级渲染,在很多场景下有用,例如loader,弹出层等;
Transition组件的核心思想是将动效的过程分为多个阶段,在挂载的钩子中动态为其添加样式。
编译器
vue.js 的模板和JSX都属于领域特定语言,它们的实现难度属于中、低级别,只要掌握基本的编译技术理论即可实现功能;
vuejs的模板编译器
工作步骤
- 分析模板,将其解析为AST模板
- 将模板AST转换为用于描述渲染函数的JavaScript AST
- 根据JavaScript AST生成渲染函数代码
AST树构成原理
- 用有限状态机构造一个词法分析器,词法分析过程就是状态机在不同状态之间迁移的过程。
- 过程中产生一个个TOKEN,形成列表
- 扫描Token列表并维护一个开始标签
- 每扫到一个开始标签节点,就将其压入栈顶,栈顶节点始终为下一扫码节点的父节点
- 扫描完毕形成树形AST
解析器
解析器本质上是一个状态机,正则表达式其实也是一个状态机,因此在编写parser的时候利用正则表达式可以更加效率;
文本模式:解析器在工作时所进入的一些特殊状态,如RCDATA,CDATA,RAWTEXT模式,以及初始DATA模式,不同的模式,解析器对文本解析会有所不同;
递归下降算法:不断递归调用解析子节点函数的过程是递归的含义,下降的含义是随着被递归调用的下降parseChildren函数去构造下级模板AST节点;
编译优化
编译优化是通过编译的手段提取关键信息,并以此指导生成最优代码的过程,关键点在区分 动态节点
与静态节点
;vue3会为动态节点打上标签,在编译时只关注动态节点的更新;
Vue.js 3 在编译优化方面还做了其他努力,具体如下:
- 静态提升:能够减少更新时创建虚拟DOM带来的性能开销和内存占用
- 预字符串化: 在镜头提升的基础上,对静态节点进行字符串化,可以减少创建虚拟节点产生的性能开销及内存占用;
- 缓存内联事件处理函数:避免造成不必要的组件更新
- v-once指令 :缓存全部或部分虚拟节点,能够避免组件更新时重新创建虚拟DOM带来的性能开销,也可以避免无用的Diff操作
服务端渲染
vue.js可以实现的渲染方式
- 客户端渲染( client-side-rendering, CSR)
- 服务端渲染(server-side-rendering, SSR)
- 同构渲染(isomorphic rendering)
渲染比对
SSR | CSR | 同构渲染 | |
---|---|---|---|
SEO | 友好 | 不友好 | 友好 |
白屏问题 | 无 | 有 | 无 |
占用服务端资源 | 多 | 少 | 中 |
用户体验 | 差 | 好 | 好 |
基于此表可以看出同构渲染是一种高级且优秀的渲染方案,实现流程:
- 服务端渲染静态HTML字符串并发送给浏览器
- 浏览器渲染静态HTML静态字符串内容
- 下载打包在静态资源中的组件代码
- 浏览器会解析并执行该组件代码
- 浏览器激活DOM
- 在虚拟节点与真实DOM元素之间建立联系,即vnode.el = el;这样才能保证后续的程序正确运行
- 为DOM元素添加事件绑定
注意事项
- 钩子函数不会在服务端执行
- 注意跨平台API
- 特定端实现,利用cookie信息,在服务端需要从请求头获取,而客户端却是document.cookie
- 避免交叉请求引起的状态污染,因为服务器的一对多特性
- 仅在客户端渲染组件中的部分内容,自行封装 组件,利用onMounted钩子函数只会在客户端运行的原理;
最后
📚 vue
☃️ 个人简介:一个喜爱技术的人。
🌞 励志格言: 脚踏实地,虚心学习。
❗如果文章还可以,记得用你可爱的小手点赞👍关注✅,我会在第一时间回、回访,欢迎进一步交流。
HTTP
-
HTTP 报文结构是怎样的?
-
HTTP有哪些请求方法?
-
GET 和 POST 有什么区别?
-
如何理解 URI?
-
如何理解 HTTP 状态码?
-
简要概括一下 HTTP 的特点?HTTP 有哪些缺点?
-
对 Accept 系列字段了解多少?
-
对于定长和不定长的数据,HTTP 是怎么传输的?
-
HTTP 如何处理大文件的传输?
-
HTTP 中如何处理表单数据的提交?
-
HTTP1.1 如何解决 HTTP 的队头阻塞问题?
-
对 Cookie 了解多少?
-
如何理解 HTTP 代理?
-
如何理解 HTTP 缓存及缓存代理?
-
为什么产生代理缓存?
-
源服务器的缓存控制
-
客户端的缓存控制
-
什么是跨域?浏览器如何拦截响应?如何解决?