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  ;# 延迟执行
  }
}