Vue源码的全方位解读(二)

    如今的声明式操作DOM都是描述状态和DOM之间的映射关系是怎样的,就可以将状态渲染成视图,现代框架揭露的事实是,我们的关注点应该聚焦在状态维护上,而DOM操作时可以省略掉的,状态可以是js中的任意类型,最终会以段落、表单、链接或按钮等元素呈现在用户界面上。当某个状态发生变化时,只更新与这个状态相关联的DOM节点。虚拟DOM的解决方式就是通过状态生成一个虚拟节点树,然后使用虚拟节点树进行渲染。在渲染之前,会使用新生成的虚拟节点树和上一次生辰的虚拟节点树进行对比,只渲染不同的部分。
    Vue.js的变化侦测和React,Angular都不一样,它在一定程度上知道具体哪些状态发生了变化,这样就可以通过更细粒度的绑定来更新视图,也就是说,在Vue.js中,当状态发生变化时,它在一定程度上知道哪些节点使用了这个这状态,从而直接对这些节点进行更新操作,但粒度太细,太多的watcher观察状态就会造成很大的内存开销。vue2.0开始引入虚拟DOM,组件级别是一个watcher实例,也就是说即使一个组件内有10个节点使用了某个状态,但其实也有只有一个watcher在观察这个状态的变化。当这个状态发生变化时,只能通知到组件,然后组件内部通过虚拟DOM去进行比对和渲染。
    在vue.js中,使用模板来描述状态与DOM之间的映射关系,Vue.js通过编译将模板转换为渲染函数(render),执行渲染函数就可以得到一个虚拟节点树,使用这个虚拟节点树就可以渲染页面。为了避免不必要的操作,虚拟DOM在将节点映射到视图的过程中,将虚拟节点与上一次渲染视图所使用的旧虚拟节点做对比,找出真正需要更新的节点来进行DOM操作,从而避免操作其他无任何改动的DOM.虚拟DOM做的事就是:1.提供与真实DOM节点相对应的虚拟节点vnode.2.将虚拟节点vnode和旧虚拟节点oldvnode进行比对然后更新视图。模板编译的主要目标就是生成渲染函数,而渲染函数的作用是每次执行它,它就会使用当前最新的状态生成一份新的vnode,然后使用这个vnode进行渲染。
    在Vue.js中存在一个VNode类,使用它可以实例化不同类型的vnode实例,而不同的vnode实例各自表示不同类型的DOM元素。vnode可以理解成节点描述对象,它描述了应该怎样去创建真实的DOM节点,vnode表示一个真实的DOM元素,所有真实的DOM节点都使用vnode创建并插入到页面中。由于每次渲染视图时都是先创建vnode,然后使用它创建真实DOM插入到页面中,所以可以将上一次渲染视图的vnode缓存起来,之后每当需要重新渲染时,将新创建的vnode和上一次缓存的vnode进行对比,查看它们之间有哪些不一样的地方,找出这些不一样的地方并基于此去修改真实的DOM.Vue采用了中等粒度的状态侦听策略,也就是当状态发生变化时,只通知到组件级别,然后组件内使用虚拟DOM来渲染视图,当某个状态发生变化时,只通知使用了这个状态的组件,也就是只要组件使用的众多状态中有一个发生了变化,那么整个组件使用状态的节点就要重新渲染。
    vnode的类型有以下几种:注释节点、文本节点、元素节点、组件节点、函数式节点、克隆节点。
    patch算法:虚拟DOM最核心的部分就是patch算法。通过这种找新旧vnode不同的方式选择性的更新DOM,之所以这么做是因为DOM的执行速度远远不如js的运算速度,因为把大量DOM操作搬到js中通过patch算法来计算出真正需要更新的节点,最大限度的减少DOM操作,从而显著提升技能。用js的运算成本来换DOM操作的执行成本。(直接操作DOM也可以完成操作,但这一切都是为了性能考虑)
    整个patch过程包括:创建新增的节点、删除已经废弃的节点、修改需要更新的节点。整个patch流程并不复杂,当oldVnode不存在时,直接使用vnode渲染视图,当oldVnode和Vnode都存在但并不是同一个节点时,使用Vnode创建的DOM元素替换旧的DOM元素,当oldVnode和vnode是同一个节点时,使用更详细的对比操作对真实的DOM节点进行更新。
    将模板编译成渲染函数可以分为两个步骤,先将模板解析成AST(抽象语法树),然后再使用AST生成渲染函数。但是由于静态节点不需要总是重新渲染,所以在生成AST之后、生成渲染函数之前这个阶段,需要做一个操作,就是遍历一遍AST,给所有的静态节点做一个标记,这样在虚拟DOM中更新节点时,如果发现节点有这个标记,就不会重新渲染它。


全部评论

相关推荐

996的工作制还是没能硬啃下去,快要面试怂了,取消了
牛客80700350...:很正常,不是所有人都能接受这种强度的。不叫怯战,这叫明智
点赞 评论 收藏
分享
xdm 早上喝奶茶差点喷出来。事情是这样的,我们班有个哥们儿,简称 L,去年秋招拿了字节sp,专业方向是后端。我们当时都震惊:这哥们儿平时课上从来不发言,期末小组作业基本是划水的那种,刷题平台 commit记录我点进去看过,绿格子稀稀拉拉。但他面试一路绿灯。一面二面三面 hr 面,全过,给的还是sp。当时班级群里恭喜他的、问他经验的、约饭的,热闹了一周。他说自己"运气好,准备充分"。我们都信了,直到三月初他入职。入职第二周开始,班里另一个进字节的同学W(在隔壁组的)开始跟我他的不对劲。一开始是写代码慢,后来写不出来,再后来是组里 mentor 让他fix 一个简单 bug 都搞了一下午没动静。最离谱的是上周。W 说他们大部门搞了个新人分享会,让新人讲一下自己负责模块的设计思路。L 上去讲了 20分钟,全程念稿子,问答环节别人随便问一个"那你这里为什么用 Redis 不用 Memcached",他直接卡 30秒说"这个我回去再确认一下"。会后他 mentor 直接找 leader 谈,leader 找 hr 谈,hr调出了他面试录像,全程对比口型和回答节奏,发现他二三面有大量时长在偷偷看屏幕外(推测开了双机位 AI 答题)。(这段是 W后来转述给我的,他自己也是听他组里同事八卦来的)昨天下班前,W 告诉我L 被辞退了,让他自己走,不走就走仲裁但会发函到学校。L 现在已经回学校了,朋友圈仅三天可见。我说真的,我不是个心眼小的人,但是我看到这个消息的时候真的有种"嗯,挺好"的感觉。去年秋招我投字节后端,简历挂。我准备了八个月,背 八股 + 刷 500 题 +项目改了三版,连面试机会都没拿到。班里这哥们儿凭着一个外挂上岸,最后还是被甩出来了。不是说作弊就一定会被发现,但是当面试拿到的 offer远远超出真实能力的时候,迟早会有这一天。试用期三个月不是给你过家家的,是真的要写代码、要在会议上回答问题、要扛需求的。我现在反而有点同情他。同情他相信"上岸就是终点"。发出来不是为了嘲笑谁,就是想说给那些正在被身边作弊上岸的同学搞得很 emo 的 uu 们听——别急,回旋镖很长,但它一定会回来。你继续刷你的题,写你的项目,背你的八股。该是你的迟早是你的,不是你的早晚还得还回去。xdm 共勉。
牛客12588360...:我不想评论面试方式,作弊是绝对不对的,但是你八股加刷题也不过是个做题小子,他穿帮纯粹是他菜,你也没有高明到哪里去
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务