Skip to content

vue是如何实现双向绑定和模板渲染的(第一反应版) #2

@Link-Fight

Description

@Link-Fight

vue是如何实现双向绑定和模板渲染的

前言

这是我小伙伴面试遇到的题目,突然想起我从vue1.5用到vue2.5,有两年的都是已vue为伴,虽然断断续续看过vue的源码,但是没有想过遇到该面试题时候,该怎么答?

以下为我第一时间想到的回答:

说起vue是如何实现其双向绑定功能的,就一定要提到ES5中提供的Object.defineProperty方法,能够为对象的属性设置getset方法,在属性进行读取以及修改的时候可以执行框架的代码。在该框架代码里面会有一个Dep对象(就是一个收集依赖的对象),当属性被读取的时候,会触发get方法里面的注入代码,当有watcher(观察者)存在的时候,Dep就会收集这些watcher(观察者)。而在属性被修改赋值的时候,会触发set方法里面注入的代码,其发现属性值被修改后,会通知Dep里面收集到watcher(观察者),由其去执行相应的代码。

而watcher的存在是通过vue提供的$watcher方法来生成watcher对象,而渲染函数render就是首先被定义为一个watcher,并且还是其回调。在渲染函数render执行的过程中,会触发到相应属性的get方法,从而被每一个触发到的属性的Dep收集起来。以此,当这些属性发生修改的时候,触发set方法,就是触发了Dep收集到的watcher的回调,从而再次渲染。当然,这里需要解决包括watcher对象以及dep对象重复收集,以及渲染函数重复执行的问题。这vue在dep收集每个watcher时候,都会检查其id是否重复,从而避免重复收集。而在通知Dep收集的watcher对象,让其重新渲染的操作是异步的,它们会被放到一个队列里面,当然在执行前会根据watcher的id进行查重。这个队列是调用vue提供的$nextTick方法来执行,原理就是把这些任务放到mirctack或marctack中执行,当执行栈外空才去执行,提供性能。

而谈到模板渲染,在vue1.x起,很多vue使用者就使用template,当时读vue1.x的时候,发现采用大量的正则表达式是去处理template字符串,把tag,属性,事件提取出来,而最终从这些信息变成dom的没去了解。而到了vue2.x,虽然还是经常使用template,但是会通过vue-loader方法把template变成render方法,就是调用了$createElemt的Vnode方法,这个方法会把目标元素先变为一个VNode,在第一次渲染时,会调用dom提供的生成dom的方法,依据Vnode树,一个个生成出来。而在数据发生改变时候,render会执行,生成新的Vnode树,而这时这些MVVM其提供性能措施就主要这这里,框架会对比新旧Vnode的差异,然后仅根据这些差异修改现有的dom结构。而对比两个Vnode的差异就是各大框架的性能瓶颈了,而vue里基于github上一个开源的库snabbbar,在原有的基础上,根据vue控件的需要在vnode的各个钩子里面注入框架的方法。

这是第一反应,想到的。比不上那些边看文档,源码的回复。
迟点会更新个论文基本的答案。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions