首页 > 代码库 > LightTable的结构(二)
LightTable的结构(二)
这节主要研究下object的一个属性,behaviors
定义一个behavior需要提供name,trigger,reaction
(behavior ::on-close-destroy :triggers #{:close} :reaction (fn [this] (object/raise this :destroy)))
在创建object的时候传入
(object/object* ::user.hello :tags [:user.hello] :behaviors [::on-close-destroy] :init (fn [this] (hello-panel this)))
在object/object*和object/create的时候都可以传入behavior
那么怎么触发behavior呢
(object/raise app :closing)
(defn raise* ([obj reactions args] (raise* obj reactions args nil)) ([obj reactions args trigger] (doseq [r reactions :let [func (:reaction (->behavior r)) args (if (coll? r) (concat (rest r) args) args) meta (if (coll? r) (meta r) {})] :when func] (try (with-time (binding [*behavior-meta* meta] (apply func obj args)) (when-not (= trigger :object.behavior.time) (raise obj :object.behavior.time r time trigger))) (catch js/Error e (safe-report-error (str "Invalid behavior: " (-> (->behavior r) :name))) (safe-report-error e) ) (catch js/global.Error e (safe-report-error (str "Invalid behavior: " (-> (->behavior r) :name))) (safe-report-error e) )))))(defn raise [obj k & args] (let [reactions (-> @obj :listeners k)] (raise* obj reactions args k)))
可以看出,object/raise会从obj的:listeners中获取对应trigger的reactions
object/raise*中,对这些reactions进行执行,那么behavior是如何变成:listener的呢,注意到 object/handle-redef 会使用update-listeners
(defn handle-redef [odef] (let [id (::type odef)] (doseq [o (instances-by-type id) :let [o (deref o) args (:args o) old (:content o) behs (set (:behaviors o)) inst (@instances (->id o)) neue (when (:init odef) (apply (:init odef) inst args)) neue (if (vector? neue) (crate/html neue) neue)]] (merge! inst {:tags (set/union (:tags o) (:tags odef)) :behaviors (set/union behs (set (:behaviors odef))) :content neue}) (merge! inst (update-listeners inst)) (when (and old neue) (replace-with old neue)) (raise inst :redef)) id))(defn object* [name & r] (-> (apply make-object* name r) (store-object*) (handle-redef)))
update-listeners利用->triggers将behavior转换成对应的 trigger,存入:listeners
(defn update-listeners ([obj] (update-listeners obj nil)) ([obj instants] (let [cur @obj behs (set (concat (:behaviors cur) (tags->behaviors (:tags cur)))) trigs (->triggers behs) ;;We need to load new JS files here because they may define the behaviors that we‘re meant to ;;capture. If we have a load, then load and recalculate the triggers to pick up those newly ;;defined behaviors trigs (if (:object.instant-load trigs) (do (raise* obj (:object.instant-load trigs) nil :object.instant-load) (->triggers behs)) trigs) trigs (if instants trigs (dissoc trigs :object.instant :object.instant-load))] ;;deref again in case :object.instant-load made any updates (assoc @obj :listeners trigs))))
(defn ->triggers [behs] (let [result (atom (transient {}))] (doseq [beh behs t (:triggers (->behavior beh))] (swap! result assoc! t (conj (or (get @result t) ‘()) beh))) (persistent! @result)))
--------------------------------------
注:
获取Ref, Atom 和Agent对应的value @ref (deref ref)
LightTable的结构(二)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。