全国咨询热线:18720358503

小程序免费制作平台_100行代码了解和分析vue2.0响

类别:媒体报道 发布时间:2021-01-12 浏览人次:

100行代码理解和分析vue2.0响应式架构       通过100行代码帮助大家理解和分析vue2.0响应式架构的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

我之前介绍过vue1.0如何实现observer和watcher。本想继续写下去,可是vue2.0横空出世..所以直接看vue2.0吧。这篇文章在公司分享过,终于写出来了。我们采用用最精简的代码,还原vue2.0响应式架构实现。

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

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

本文分享什么

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


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

本分实现什么

const demo = new Vue({
 data: {
 text: "before",
 //对应的template 为 div span {{text}} /span /div 
 render(h){
 return h('div', {}, [
 h('span', {}, [this.__toString__(this.text)])
 setTimeout(function(){
 demo.text = "after"
 }, 3000)

对应的虚拟dom会从

div span before /span /div 变为 div span after /span /div

好,开始吧!!!

第一步,讲data 下面所有属性变为observable

来来来先看代码吧

 class Vue {
 constructor(options) {
 this.$options = options
 this._data = options.data
 observer(options.data, this._update)
 this._update()
 _update(){
 this.$options.render()

function observer(value, cb){ Object.keys(value).forEach((key) = defineReactive(value, key, value[key] , cb)) function defineReactive(obj, key, val, cb) { Object.defineProperty(obj, key, { 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)

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

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

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

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

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

 _proxy(key) {
 const self = this
 Object.defineProperty(self, key, {
 configurable: true,
 enumerable: true,
 get: function proxyGetter () {
 return self._data[key]
 set: function proxySetter (val) {
 self._data[key] = val

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

Object.keys(options.data).forEach(key = this._proxy(key))

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

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

比如考虑下面代码

 new Vue({
 template: `
 div 
 section 
 span name: /span {{name}}
 /section 
 section 
 span age: /span {{age}}
 /section 
 div `,
 data: {
 name: 'js',
 age: 24,
 height: 180
 setTimeout(function(){
 demo.height = 181
 }, 3000)

template里面只用到了data上的两个属性name和age,但是当我改变height的时候,用第一步的代码,会不会触发重新渲染?会!,但其实不需要触发重新渲染,这就是问题所在!!

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

 function VNode(tag, data, children, text) {
 return {
 tag: tag,
 data: data,
 children: children,
 text: text
 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, attr, children.map((child)= {
 if(typeof child === 'string'){
 return VNode(undefined, undefined, undefined, child)
 }else{
 return child
 __toString__(val) {
 return val == null '' : typeof val === 'object' JSON.stringify(val, null, 2) : String(val);

tag: undefined, text: '' // 正常情况为 字符串 before,因为我们为了演示就不写代理的代码,所以这里为空

这就是 虚拟最简单虚拟DOM,tag是html 标签名,data 是包含诸如class和style这些标签上的属性,childen就是子节点,关于虚拟DOM就不展开说了。

回到开始的问题,也就是说,我得知道,render 函数里面依赖了vue实例里面哪些变量(只考虑render 就可以,因为template 也会是帮你编译成render)。叙述有点拗口,还是看代码吧

 var demo = new Vue({
 el: '#demo',
 data: {
 text: "before",
 name: "123",
 age: 23
 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上的属性设置defineReactive后,修改data 上的值会触发set。
那么我们取data上值是会触发get了。
对,我们可以在上面做做手脚,我们先执行一下render,我们看看data上哪些属性触发了get,我们岂不是就可以知道 render 会依赖data 上哪些变量了。
然后我么把这些变量做些手脚,每次这些变量变的时候,我们就触发render。
上面这些步骤简单用四个子概括就是 计算依赖。
(其实不仅是render,任何一个变量的改别,是因为别的变量改变引起,puted 和 watch 的原理,也是mobx的核心)

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

 class Dep {
 constructor() {
 this.subs = []
 add(cb) {
 this.subs.push(cb)
 notify() {
 console.log(this.subs);
 this.subs.forEach((cb) = cb())
 function defineReactive(obj, key, val, cb) {
 const dep = new Dep()
 Object.defineProperty(obj, key, {
 // 省略

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

 function VNode(tag, data, children, text) {
 return {
 tag: tag,
 data: data,
 children: children,
 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, key, {
 configurable: true,
 enumerable: true,
 get: function proxyGetter () {
 return self._data[key]
 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, attr, children) {
 return VNode(tag, attr, children.map((child)= {
 if(typeof child === 'string'){
 return VNode(undefined, undefined, undefined, child)
 }else{
 return child
 __toString__(val) {
 return val == null '' : typeof val === 'object' JSON.stringify(val, null, 2) : String(val);
 function observer(value, cb){
 Object.keys(value).forEach((key) = defineReactive(value, key, value[key] , cb))
 function defineReactive(obj, key, val, cb) {
 const dep = new Dep()
 Object.defineProperty(obj, key, {
 enumerable: true,
 configurable: true,
 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

我们看一下运行结果


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

 function watch(vm, exp, cb){
 Dep.target = cb
 return exp()

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

 get: () = {
 if (Dep.target) {
 dep.add(Dep.target)
 return val

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

总结

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

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

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



而vue2.0 天然帮你做到了最优,而且对于像万年不变的 如标签上静态的class属性,vue2.0 在重新渲染后做diff 的时候是不比较的,vue2.0比达到性能最大化的react 还要快的一个原因。
然后在此,喜欢的记得给个star 哦
后续,我会简单聊聊,vue2.0的diff。

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

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

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


推荐阅读

小程序免费制作平台_100行代码了解和分析vue2.0响

100行编码了解和剖析vue2.0响应式构架 根据100行编码协助大伙儿了解和剖析vue2.0响应式构架的有关材料,具备一定的参照使用价值,很感兴趣的小伙子伴们能够参照一下我以前详细...

2021-01-12
如何缩短网站被搜索引擎收录的时间

怎样减少网站被检索模块百度收录的時间:google新网站的百度收录速率是较为快的,一般新网站发布以后,您只必须在好多个权重值高的网站里公布2~3篇推广软文,沒有出现意外的状况...

2021-01-12
互联网时代,你会被淘汰吗?

企业动态性制造行业新闻资讯建网站有关九度角度强烈推荐信息内容 互连网时期,你能淘汰吗? 重要词:自主创新 意识 专业技能 学习培训 消費方式 情商智商 项目投资 互连网 每个人...

2021-01-12
美司法部调查华为,美司法部调查华为,指控比中

重要词:美司法部门部调研华为公司,美司法部门部调研华为公司,控告比zte中兴更比较严重!华为公司:空穴来风 现有 2797 人访问 4月2五日,美国华尔街日报引证知情人人员的信息报导称...

2021-01-12
网站运营者必看之网络营销三部曲

互联网营销推广这一词自问世具有现如今,早已被普遍的运用及其被众多的中小型公司所接纳和认同。发展趋势到如今,实际来讲现有四年上下的時间了(按2012年宣布刚开...

2021-01-12
广州凡科互联网科技股份有限公司招聘京东推广

招聘人数:10职位信息1、负责对店铺推广数据进行分析并建立推广计划;2、通过京东快车、京东直投、京挑客、活动等推广优化店铺;3、定期分析统计店铺各项数据,及时提出改进建议...

2021-01-12
X

400-8700-61718720358503
企业邮箱2639601583@qq.com
官方微信