对大前端的思考
架构师
- 客户的想法(需求)和执行人(开发)直接有一段距离,这个距离就需要架构师的工作
- 架构师的工作就是把客户的想法和执行人的想法连接起来,把客户的想法和执行人的想法连接起来
- 架构师做的就是结构的设计与实现,需要具备解决复杂问题的能力
分析vue的架构
- 目标: 分析vue的架构,了解vue的架构设计,了解vue的架构设计的目的和意义
- 实现
目标
- vue框架的最大的特点是什么
- 可以实现视图和数据的关联
- 什么是视图
- 视图可以算是虚拟dom,也算是一种数据
- 就是数据和数据的关联
- 但数据和数据关联不存在,例如excel,求和之后,那个单元格背后其实是一个求和公式
- 即是数据与计算的关联
- 我们需要将视图的意思尽量往计算的方向去靠拢
- 得出结论
- 创建视图的过程和数据发生了关联
- 而过程,一般表现为函数或者方法,即创建视图的函数与数据产生了关联
- 创建视图的方法,我们假设叫他render
- 希望函数用到的数据发生变化的时候,render函数会重新执行,返回修改后的数据,这样就实现了视图和数据的关联
- 函数运行过程中用到了哪些数据,就关联哪些数据
- 与函数运行过程中用到的标记数据产生关联
- 需要建立对应关系(函数-数据)
- 总结
- vue框架的最大的特点可以被描述为: 函数运行过程中用到的标记数据,与函数产生关联,需要建立对应关系(函数-数据)
- 监听数据的读取和修改
- 如何知晓数据对应的函数
- 建立对应关系就是依赖收集
- vue框架的最大的特点可以被描述为: 函数运行过程中用到的标记数据,与函数产生关联,需要建立对应关系(函数-数据)
监听数据的读取和修改
有2种方式 这两个东西都要求数据是对象
- defineProperty
- 监听的范围很窄,只能监听对象的属性
- 只能通过属性描述符监听已有属性的描述和修改
- 优点是兼容性更好
- proxy
- 监听的范围很广
- 语法层面的书写,会转变为内部方法的调用
data.a = 1 => Reflect.set(data, 'a', 1)
a in data => Reflect.has(data, 'a')
- 这些内部方法都可以被proxy进行拦截
- es6的语法,可以使用proxy进行监听,不兼容低版本浏览器
- 这个被标记的数据在vue里面被称之为响应式数据
- 响应式数据就是,当这个数据发生改变的时候,重新运行一次这个函数
- 用简单的例子描述被用到的数据(即需要被响应式的数据)
js
let data1 = true, data2, data3
const fn = ()=> {
if(data1) {
data2 // data2是被用到的数据,需要被响应式
} else {
data3 // 不用被关联,不需要响应式
}
}
// 在vue里面,表示一个被标记的响应式数据
let proxyData = tag(data)
const tag = (data) => {
return new Proxy(data, {
get(target, key) {
// 返回对象的属性值
return target[key]
// 依赖收集
// 当数据被读取的时候,需要收集依赖了该数据的函数
// 即当数据被读取的时候,需要收集使用了这个数据的函数
// 这个函数就是当前的函数
track(target, key)
},
set(target, key, value) {
// 设置对象的属性值
// target[key] = value
// 建议使用反射赋值,因为它本身会返回一个布尔值
// 赋值成功返回true,失败返回false
return Reflect.set(target, key, value)
// 对应函数重新执行的过程,我们称之为派发更新
// 需要对哪个对象的哪个属性进行派发更新,就需要知道这个对象的哪个属性
tigger(target, key)
}
})
}
// 在vue3里面,这个tag方法名字叫做reactive方法
// 即
let proxyData = reactive(data)
let data1 = true, data2, data3
const fn = ()=> {
if(data1) {
data2 // data2是被用到的数据,需要被响应式
} else {
data3 // 不用被关联,不需要响应式
}
}
// 在vue里面,表示一个被标记的响应式数据
let proxyData = tag(data)
const tag = (data) => {
return new Proxy(data, {
get(target, key) {
// 返回对象的属性值
return target[key]
// 依赖收集
// 当数据被读取的时候,需要收集依赖了该数据的函数
// 即当数据被读取的时候,需要收集使用了这个数据的函数
// 这个函数就是当前的函数
track(target, key)
},
set(target, key, value) {
// 设置对象的属性值
// target[key] = value
// 建议使用反射赋值,因为它本身会返回一个布尔值
// 赋值成功返回true,失败返回false
return Reflect.set(target, key, value)
// 对应函数重新执行的过程,我们称之为派发更新
// 需要对哪个对象的哪个属性进行派发更新,就需要知道这个对象的哪个属性
tigger(target, key)
}
})
}
// 在vue3里面,这个tag方法名字叫做reactive方法
// 即
let proxyData = reactive(data)
- effect.js
js
// 依赖收集
export const track = (target, key) => {
}
// 派发更新
export const tigger = (target, key) => {
}
// 依赖收集
export const track = (target, key) => {
}
// 派发更新
export const tigger = (target, key) => {
}
- 测试使用
js
import { reactive } from './reactive.js'
const state = reactive({
a: 1,
b: 2
})
function fn() {
state.a
state.b
}
fn()
state.a ++
import { reactive } from './reactive.js'
const state = reactive({
a: 1,
b: 2
})
function fn() {
state.a
state.b
}
fn()
state.a ++
- 上面reactive.js和effect.js两个内容加起来,就是响应式系统的实现
- 响应式系统的目标就是要实现一个函数以及这一块的数据,他们之间建立对应关系
- 由于响应式系统的函数,它并不一定是渲染函数,他可以是任何普通函数
- 所以响应式系统在整个vue的源吗中是相对独立的