100行代码理解和分析vue2.0响应式架构

前端之家收集整理的这篇文章主要介绍了100行代码理解和分析vue2.0响应式架构前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

分享前啰嗦

我之前介绍过vue1.0如何实现文章在公司分享过,终于写出来了。我们采用用最精简的代码,还原vue2.0响应式架构实现。

以前写的那篇 可以作为本次分享的参考。

不过不看也没关系,但是最好了解下

本文分享什么

理解vue2.0的响应式架构,就是下面这张图

顺带介绍他比react快的其中一个原因

本分实现什么

{{text}}
render(h){ return h('div',{},[ h('span',[this.__toString__(this.text)]) ]) } }) setTimeout(function(){ demo.text = "after" },3000)

对应的虚拟dom会从

before

变为after

好,开始吧!!!

第一步,

讲data 下面所有属性变为observable

来来来先看代码

function observer(value,cb){
Object.keys(value).forEach((key) => defineReactive(value,key,value[key],cb))
}

function defineReactive(obj,val,cb) {
Object.defineProperty(obj,{
enumerable: true,configurable: true,get: ()=>{},set:newVal=> {
cb()
}
})
}

var demo = new Vue({
el: '#demo',data: {
text: 123,render(){
console.log("我要render了")
}
})

setTimeout(function(){
demo._data.text = 444
},3000)

为了好演示我们只考虑最简单的情况,如果看了可能就会很好理解,不过没关系,我们三言两语再说说,这段代码要实现的功能就是将

中data 里面所有的属性置于 observer,然后data里面的属性,比如 text 以改变,就引起_update()函数调用进而重新渲染,是怎样做到的呢,我们知道其实就是赋值的时候就要改变对吧,当我给data下面的text 赋值的时候 set 函数就会触发,这个时候 调用 _update 就ok了,但是

demo._data.text没有demo.text用着爽,没关系,我们加一个代理

然后在Vue的constructor加上下面这句

this._proxy(key))

第一步先说到这里,我们会发现一个问题,data中任何一个属性的值改变,都会引起 _update的触发进而重新渲染,属性这显然不够精准啊

第二步,

详细阐述第一步为什么不够精准

比如考虑下面代码

name: {{name}}
age: {{age}}
`,data: { name: 'js',age: 24,height: 180 } })

setTimeout(function(){
demo.height = 181
},3000)

第三步,

上述问题怎么解决 简单说说虚拟 DOM 首先,template最后都是编译成render函数的(具体怎么做,就不展开说了,以后我会说的),然后render 函数执行完就会得到一个虚拟DOM,为了好理解我们写写最简单的虚拟DOM

class Vue {
constructor(options) {
this.$options = options
const vdom = this._update()
console.log(vdom)
}
_update() {
return this._render.call(this)
}
_render() {
const vnode = this.$options.render.call(this)
return vnode
}
h(tag,attr,children) {
return VNode(tag,children.map((child)=>{
if(typeof child === 'string'){
return VNode(undefined,undefined,child)
}else{
return child
}
}))
}
toString(val) {
return val == null ? '' : typeof val === 'object' ? JSON.stringify(val,null,2) : String(val);
}
}

var demo = new Vue({
el: '#demo',data: {
text: "before",render(){
return this.h('div',[
this.h('span',[this.toString(this.text)])
])
}
})

我们运行一下,他会输出

这就是 虚拟最简单虚拟

回到开始的问题,也就是说,我得知道,

就像这段代码,render 函数里其实只依赖text,并没有依赖name和age,所以,我们只要text改变的时候,我们自动触发render 函数 让它生成一个虚拟DOM就ok了(剩下的就是这个虚拟DOM和上个虚拟DOM做比对,然后操作真实DOM,只能以后再说了),那么我们正式考虑一下怎么做

第三步,

'touch' 拿到依赖

回到最上面那张图,我们知道

第一步:

我们写一个依赖收集的类,每一个data 上的对象都有可能被render函数依赖,所以每个属性在defineReactive时候就初始化它,简单来说就是这个样子的。

cb()) } } function defineReactive(obj,cb) { const dep = new Dep() Object.defineProperty(obj,{ // 省略 }) }

然后,当执行render 函数去'touch'依赖的时候,依赖到的变量get就会被执行,然后我们就可以把这个 render 函数加到 subs 里面去了。 当我们,set 的时候 我们就执行 notify 将所有的subs数组里的函数执行,其中就包含render 的执行。 至此就完成了整个图,好我们将所有的代码展示出来

<div class="jb51code">
<pre class="brush:js;">
function VNode(tag,text: text
}
}

class Vue {
constructor(options) {
this.$options = options
this._data = options.data
Object.keys(options.data).forEach(key => this._proxy(key))
observer(options.data)
const vdom = watch(this,this._render.bind(this),this._update.bind(this))
console.log(vdom)
}
_proxy(key) {
const self = this
Object.defineProperty(self,set: function proxySetter (val) {
self._data.text = val
}
})
}
_update() {
console.log("我需要更新");
const vdom = this._render.call(this)
console.log(vdom);
}
_render() {
return this.$options.render.call(this)
}
h(tag,2) : String(val);
}
}

function observer(value,get: ()=>{
if(Dep.target){
dep.add(Dep.target)
}
return val
},set: newVal => {
if(newVal === val)
return
val = newVal
dep.notify()
}
})
}
function watch(vm,exp,cb){
Dep.target = cb
return exp()
}

class Dep {
constructor() {
this.subs = []
}
add(cb) {
this.subs.push(cb)
}
notify() {
this.subs.forEach((cb) => cb())
}
}
Dep.target = null

var demo = new Vue({
el: '#demo',[this.toString(this.text)])
])
}
})

setTimeout(function(){
demo.text = "after"
},3000)

我们看一下运行结果

好我们解释一下 Dep.target 因为我们得区分是,普通的get,还是在查找依赖的时候的get,所有我们在查找依赖时候,我们将

Dep.target 赋值,相当于 flag 一下,然后 get 的时候

{ if (Dep.target) { dep.add(Dep.target) } return val },

判断一下,就好了。到现在为止,我们再看那张图是不是就清楚很多了?

总结

我非常喜欢,vue2.0 以上代码为了好展示,都采用最简单的方式呈现。

不过整个代码执行过程,甚至是命名方式都和vue2.0一样。

对比react,vue2.0 自动帮你监测依赖,自动帮你重新渲染,而react 要实现性能最大化,要做大量工作,比如我以前分享的:

而vue2.0 天然帮你做到了最优,而且对于像万年不变的 如标签上静态的在此,喜欢的记得给个star 哦 后续,我会简单聊聊,vue2.0的diff。

本文已被整理到了《》,欢迎大家学习阅读。

关于vue.js组件的教程,请大家点击专题进行学习。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程之家。

猜你在找的Vue相关文章