《深入浅出vue.js》阅读笔记之(object)变化侦测
1、什么是变化侦测?
通常,在运行时应用内部的状态会不断发生变化,此时需要不停地重新渲染页面,这时如何确定状态中发生了什么变化?
变化侦测就是用来解决这个问题的,它分为两种类型,一种是“推”(push),另一种是拉(pull)。
angular和react的变化侦测属于“拉”,即当状态发生变化时,它不知道那个状态变了,只知道状态可能变了,然后会发送一个信号通知框架,框架内部收到信号后,就会进行对比找出哪些dom需要重新渲染,在angular中称为脏检查,在react中则使用虚拟dom。
而vue框架的变化侦测属于“推”。当状态发生变化时,vue立刻就知道了,而且在一定程度上知道哪些状态变了。因此,它知道的信息更多,也就可以进行更细粒度的更新。
所谓细粒度的更新,也就是说,假如一个状态绑定了好几个依赖,每个依赖表示一个具体的dom节点,那么当这个状态发生变化时,向这个状态的所有依赖发送通知进行dom更新操作,也可以看出“拉”的粒度是最粗的。
2、如何追踪变化?
两种方法,Object.defineProperty和es6的Proxy。由于es6在浏览器中的支持度并不理想,所以vue使用的是第一种。
知道了Object.defineProperty可以侦测对象的变化,那就可以写出以下的代码:
function defineReactive (data, key, val) {
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get: function () {
return val
},
set: function (newval) {
if (val === newval) {
return
}
val = newval
}
})
}
该函数作用是定义一个响应式数据,也就是在这个函数中进行追踪变化,当从data的key中读取数据时,get函数被触发;当从data的key中设置数据时,set函数被触发。
3、如何收集依赖?
我们之所以要观察数据,目的是当数据的属性发生变化时,可以通知那些曾经使用了该数据的地方。
例如:
<template>
<h1>{{name}}</h1>
</template>
该模版中使用了name,当它发生变化时,要向使用了它的地方发送通知。
实现的方法是,把用到数据name的地方收集起来,然后属性发生变化时,把之前收集好的依赖循环触发一遍。也就是在getter中收集依赖,setter中触发依赖。
4、依赖收集在哪里?
首先想到的是每个key都有一个数组,用来存储当前key的依赖。假设依赖是一个函数,保存在window.target上,现在可以把上面的defineReactive函数改造下:
function defineReactive (data, key, val) {
let dep = [] //new
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get: function () {
dep.push(window.target)
return val
},
set: function (newval) {
if (val === newval) {
return
}
// new
for (let i=0;i<dep.length;i++) {
dep[i](newval, val)
}
val = newval
}
})
}
这里新增了数组dep,用来存储被收集的依赖,然后在set被触发时,循环dep以触发收集到的依赖。
这里可以专门封装一个帮助我们管理依赖的类,用来收集、删除和发送通知的类:
export default class dep {
constructor () {
this.subs = []
}
addSub (sub) {
this.subs.push(sub)
}
removeSub (sub) {
remove(this.sub, sub)
}
depend () {
if (window.target) {
this.addSub(window.target)
}
}
notify () {
const subs = this.subs.slice()
for (let i=0,l = subs.length;i<1;i++) {
subs[i].update()
}
}
}
function remove (arr, item) {
if (arr.length) {
const index = arr.indexOf(item)
if (index > -1) {
return arr.splice(index, 1)
}
}
}
再改造下之前的函数:
function defineReactive (data, key, val) {
let dep = new dep() //update
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get: function () {
dep.depend()
return val
},
set: function (newval) {
if (val === newval) {
return
}
val = newval
// new
dep.notify()
}
})
}
这样就清晰很多了
《深入浅出vue.js》阅读笔记之(object)变化侦测的更多相关文章
- 《深入浅出vue.js》阅读笔记之数组变化侦测
1.如何追踪变化 数组的侦测方式和对象不同,比如: this.list.push(1) 此时并不会像改变对象一样触发setter. 同理,要侦测数组的变化意味着我们在改变数组的时候得到通知,如图,我们 ...
- vue.js 学习笔记3——TypeScript
目录 vue.js 学习笔记3--TypeScript 工具 基础类型 数组 元组 枚举 字面量 接口 类类型 类类型要素 函数 函数参数 this对象和类型 重载 迭代器 Symbol.iterat ...
- Vue.js学习笔记(2)vue-router
vue中vue-router的使用:
- Vue.js学习笔记:在元素 和 template 中使用 v-if 指令
f 指令 语法比较简单,直接上代码: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" " ...
- JDK1.8源码阅读笔记(1)Object类
JDK1.8源码阅读笔记(1)Object类 Object 类属于 java.lang 包,此包下的所有类在使⽤时⽆需⼿动导⼊,系统会在程序编译期间⾃动 导⼊.Object 类是所有类的基类,当⼀ ...
- 手牵手,从零学习Vue源码 系列二(变化侦测篇)
系列文章: 手牵手,从零学习Vue源码 系列一(前言-目录篇) 手牵手,从零学习Vue源码 系列二(变化侦测篇) 陆续更新中... 预计八月中旬更新完毕. 1 概述 Vue最大的特点之一就是数据驱动视 ...
- Vue.js——学习笔记
Vue-自学笔记 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架.与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用.Vue 的核心库只关注视图层,不仅 ...
- Vue.js 学习笔记 第4章 v-bind 及 class与style绑定
本篇目录: 4.1 了解v-bind指令 4.2 绑定class的几种方式 4.3 绑定内联样式 DOM元素经常会动态地绑定一些class类名或style样式,本章将介绍使用v-bind指令来绑定cl ...
- Vue.js——学习笔记(一)
Vue-自学笔记 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架.与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用.Vue 的核心库只关注视图层,不仅 ...
随机推荐
- kali中设置共享文件夹
1.在虚拟机设置共享目录 2.查看共享目录命令 root@kali:~# vmware-hgfsclient 3.新建文件夹 root@kali:~# mkdir /mnt/hgfs/ShareDir ...
- 手写Spring框架,是时候撸个AOP与Bean生命周期融合了!
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 嘎小子,这片代码水太深你把握不住! 在电视剧<楚汉传奇>中有这么一段刘邦 ...
- R在ubuntu16.04上环境搭建
1.R安装 sudo apt-get update sudo apt-get remove vim-common sudo apt-get install vimapt-cache show r-ba ...
- vue(24)网络请求模块axios使用
什么是axios Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中. 主要的作用:axios主要是用于向后台发起请求的,还有在请求中做更多是可控功能. a ...
- Spring in Action学习笔记(1)
Spring基础 IoC 控制反转, 也称为DI-依赖注入 一.装配bean 推荐顺序:自动装配 -> JavaConfig装配 -> XML装配 1. 自动装配 @Component 注 ...
- php header 设置文件下载
控制器 php 代码: $filepath = "http://www.jiesen365.com/uploadfile/20150519044903-897.pdf"; //下载 ...
- CFS靶机
nmap扫描 nmap -sV -p1-65535 192.168.1.135 thinkphp5.0版本 找到poc进行测试 http://192.168.1.135/index.php?s=ind ...
- CF474D Flowers 题解
题目:CF474D Flowers 传送门 DP?递推? 首先可以很快看出这是一道 DP 的题目,但与其说是 DP,还不如说是递推. 大家还记得刚学递推时教练肯定讲过的一道经典例题吗?就是爬楼梯,一个 ...
- JS的FileSaver在Chrome上保存失败
在使用JavaSript的FileSaver保存文件时,IE11上好的,chrome上反没响应,不能保存文件.寻找了半天,最好发现是因为在FileSaver之外还有一个自定义的全局URL变量,把这个U ...
- Java面向对象05——创建对象内存分析