React to Data Change - 响应数据的变化
MobX 是一个用来响应数据变化的 JavaScript 框架。
From Data to View - Explicitly
set app_state(count) 3
proc @app-view {} {
puts $::app_state(count)
}
proc @app-action {} {
incr ::app_state(count)
@app-view ;# Explicitly 触发 View 的更新
}
event every 1000ms @app-action
vwait forever
From Explicitly to Implicitly
proc @app-action {} {
incr ::app_state(count)
if {0} {
@app-view ;# -- Implicitly 交由外部逻辑自动触发
}
}
# -- 在这里 Implicitly
trace add variable app_state write @app-view
Just-In-Time Compiler
@observable app_state
@observer @app-view
# trace add variable app_state write @app-view
Want It to Be
set app_state(count) 3
proc @app-view {} {
puts $::app_state(count)
}
proc @app-action {} {
incr ::app_state(count)
}
@observable app_state
@observer @app-view
event every 1000ms @app-action
vwait forever
React with Tcl
对外接口主要是 @observable
和 @observer
proc @observable {state_var} {
set state_var [namespace which -variable $state_var]
trace add variable $state_var read @trigger-collect $state_var
trace add variable $state_var write @trigger-observer
}
proc @observer {command} {
set ::current_observer $command
uplevel 1 $command
set ::current_observer {}
}
一种简单的实现
proc @trigger-collect {state_var args} {
if {$::current_observer eq ""} return
@observer-link $state_var $current_observer
}
proc @trigger-observer {state_var args} {
dict for {observer meta} [@observer-of $stage_var] {
@observer-call $observer $meta
}
}
proc @observer-link {stage_var observer} {
dict set ::observer_map $state_var $::current_observer {}
}
proc @observer-of {stage_var} {
return [dict get $::observer_map $state_var]
}
proc @observer-call {observer meta} {
$observer
}
性能优化
上面的原型实现有个性能上的问题。状态数据的每次更新都会触发视图更新,而这并不必要。
很多时候完全可以将连续的多次状态操作合并看作一次整体的操作,然后一次性的进行视图的更新。
这就需要延迟执行代码的执行。
proc @observer-call {observer meta} {
if {0} {
$observer
} else {
after idle $observer ;# 延迟执行
}
}