We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
onStateChanged(() => { view = render(state) })
将整个响应式系统抽象为一个onStateChanged方法,view自动根据state的变化而变化
onStateChanged
那么如何实现onStateChanged呢?
先看下手动触发更新是怎么写的
let update; const onStateChanged = _update => { update = _update; } const setState = newState => { state = newState; update(); }
每次更新时传入newState: {a: 1}, 手动触发setState
newState
{a: 1}
onStateChanged(() => { view = render(state) }) setState({ a: 1})
用过react的同学会发现,这就是整个react的工作核心。
那么,如果我不想手动setState,只想改变状态state.a = 2,然后view自动更新,如何做到autorun呢?
setState
state.a = 2
autorun
我们都知道NG是采用脏检测的方式(这里不展开叙述)
而vue是通过ES5的object.defineProperty()方法把数据对象变成响应式的可观察对象(observable),把所有属性转为getters和setters,这些 getter/setter对用户来说是不可见的,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化,这段话暂时不理解没关系,我们后面再回来理解。
object.defineProperty()
getters
setters
getter/setter
autorun(() => { console.log(state.count) })
这里是整个vue追踪变化的核心
下面我们尝试来自己实现一个最简单的响应式系统,主要分三块
dependency-tracking
mini-observer
function convert (obj) { // 取出obj的每个key进行循环将整个obj所有属性都变成getter/setter Object.keys(obj).forEach(key => { // 这里其实是个闭包,需要取得初始值,不然初始化可能会拿到underfined let internalValue = obj[key]; Object.defineProperty(obj, key, { get() { console.log(`getting key "${key}": ${internalValue}`); return internalValue; }, set(newValue) { console.log(`setting key "${key}" to: ${newValue}`); internalValue = newValue; } }) }) }
实现效果如下
const obj = { foo: 123 } convert(obj) obj.foo // 'getting key "foo": 123' obj.foo = 234 // 'setting key "foo" to 234' obj.foo // 'getting key "foo": 234'
Dep
depend
notify
dep.depend()
dep.notify()
先看我们要实现的效果
const dep = new Dep() autorun(() => { dep.depend() console.log('updated') }) // should log: "updated" dep.notify() // should log: "updated"
Dep是一个class, 它有两个方法: depend和notify,顾名思义,一个是收集依赖,一个通知更新
class
无论何时调用dep.notify(), 传给autorun的方法应该再次 自动执行
// 订阅者Dep 主要作用是存放watcher观察者对象 // 这里为了简化概念,没有引入watcher,直接用变量替代 // 下面重点讲到的activeUpdate 类似于Dep.target = this; class Dep { constructor() { // Set类数组,成员唯一不重复 this.subscribes = new Set(); } // 依赖收集,其实就是收集watcher depend() { if (activeUpdate) { this.subscribes.add(activeUpdate) } } // 通知所有watcher对象更新视图 notify() { this.subscribes.forEach(sub => sub()); } }
接下来看下autorun的实现
let activeUpdate = null function autorun (update) { const wrappedUpdate = () => { activeUpdate = wrappedUpdate; update(); activeUpdate = null; } wrappedUpdate() }
这里需要好好理解一下 activeUpdate是一个autorun之外的变量 每当autorun执行,activeUpdate = wrappedUpdate代表的是autorun内正在执行的整个模块,如下图
activeUpdate
activeUpdate = wrappedUpdate
在依赖收集
depend() { // 将整个`autorun`内正在执行的整个模块,也就是watcher存放到订阅列表中 if (activeUpdate) { this.subscribes.add(activeUpdate) } }
结合上面两个模块
class Dep { constructor () { this.subscribers = new Set() } depend () { if (activeUpdate) { this.subscribers.add(activeUpdate) } } notify () { this.subscribers.forEach(sub => sub()) } } function observe (obj) { // 遍历对象所有属性,并全部转为getter/setters Object.keys(obj).forEach(key => { let internalValue = obj[key] // 每个属性都有一个订阅实例 const dep = new Dep() Object.defineProperty(obj, key, { // getter 负责依赖收集 get () { dep.depend() return internalValue }, // setter 负责通知更新 set (newVal) { const changed = internalValue !== newVal internalValue = newVal // 触发计算,视图更新 if (changed) { dep.notify() } } }) }) return obj } let activeUpdate = null function autorun (update) { const wrappedUpdate = () => { activeUpdate = wrappedUpdate update() activeUpdate = null } wrappedUpdate() }
可以测试一下如下代码
const state = { count: 0 } observe(state) autorun(() => { console.log(state.count) }) // "count is: 0" state.count++ // "count is: 1"
The text was updated successfully, but these errors were encountered:
早
Sorry, something went wrong.
nice
No branches or pull requests
高级抽象
将整个响应式系统抽象为一个
onStateChanged
方法,view自动根据state的变化而变化那么如何实现
onStateChanged
呢?先看下手动触发更新是怎么写的
每次更新时传入
newState
:{a: 1}
, 手动触发setState用过react的同学会发现,这就是整个react的工作核心。
那么,如果我不想手动
setState
,只想改变状态state.a = 2
,然后view自动更新,如何做到autorun
呢?我们都知道NG是采用脏检测的方式(这里不展开叙述)
而vue是通过ES5的
object.defineProperty()
方法把数据对象变成响应式的可观察对象(observable),把所有属性转为getters
和setters
,这些getter/setter
对用户来说是不可见的,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化,这段话暂时不理解没关系,我们后面再回来理解。这里是整个vue追踪变化的核心
下面我们尝试来自己实现一个最简单的响应式系统,主要分三块
getter/setter
dependency-tracking
mini-observer
将数据对象转成
getter/setter
Object.defineProperty
log all the get/set operations.
实现效果如下
实现依赖追踪
dependency-tracking
Dep
class with two methods:depend
andnotify
.autorun
function that takes an updater function.Dep
by callingdep.depend()
dep.notify()
.先看我们要实现的效果
Dep
是一个class
, 它有两个方法:depend
和notify
,顾名思义,一个是收集依赖,一个通知更新无论何时调用
dep.notify()
, 传给autorun
的方法应该再次 自动执行接下来看下
autorun
的实现这里需要好好理解一下
activeUpdate
是一个autorun
之外的变量每当
autorun
执行,activeUpdate = wrappedUpdate
代表的是autorun
内正在执行的整个模块,如下图在依赖收集
mini-observer
结合上面两个模块
可以测试一下如下代码
The text was updated successfully, but these errors were encountered: