这节主要研究下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的结构(二)的更多相关文章

  1. PostgreSQL的存储系统二:REDOLOG文件存储结构二

    REDOLOG文件里的用户数据和数据文件里的用户数据存储结构相同 几个月前同事给台湾一家公司培训<pg9 ad admin>时,有个学员提及WAL里记录的内容为Query时的SQL语句(比 ...

  2. JAVA的选择结构(二)

    1.switch选择结构:                        语法:                            switch (key) {                   ...

  3. update_engine-整体结构(二)

    在update_engine-整体结构(一)中分析UpdateEngineDaemon::OnInit()的整体情况.下面先分析在该方法中涉及的DaemonStateAndroid和BinderUpd ...

  4. java虚拟机规范(se8)——java虚拟机结构(二)

    2.5 运行时数据区域 java虚拟机定义了多个用于程序执行期间的运行时数据区域.这些数据区域中一些随着java虚拟机的启动而创建,随着虚拟机的退出而销毁.其他的数据区域时和线程相关的.线程相关数据区 ...

  5. Flask从入门到精通之大型程序的结构二

    一.程序包 程序包用来保存程序的所有代码.模板和静态文件.我们可以把这个包直接称为app(应用),如果有需求,也可使用一个程序专用名字.templates 和static 文件夹是程序包的一部分,因此 ...

  6. PLSQL中使用二维存储结构---二维数组

    代码如下:  --PLSQL中没有数组的概念 用TYPE 和Table of Record来代替多维数组--create by jenrry 20171028-- 1.0 建立存放列的测试表creat ...

  7. LightTable的结构(一)

    LightTable使用clojurescript来生成js,然后使用 node-webkit 来处理UI clojurescript非常适合做抽象程度很高的页面和编辑逻辑结构设计, 最近会对整体进行 ...

  8. Linux目录结构(二)

    Linux文件系统结的结构是树形结构,其入口从/开始,了解Linux文件系统的结构,对于我们需要掌握的基础知识点之一. 2.文件系统的组织结构简说: 当您使用Linux的时候,如果您通过ls -la ...

  9. java6循环结构二

    public class jh_01_回顾与作业点评 { public static void main(String[] args) { int val = 12345; System.out.pr ...

随机推荐

  1. vue 画二维码

    首先安装一下相关的插件 qrcode2 npm install --save qrcode2 然后在需要画二维码的页面引入一下 import QRCode from 'qrcode2' 最后在meth ...

  2. NOIp十连测 涂色游戏

    [问题描述]小A 和小B 在做游戏.他们找到了一个n 行m 列呈网格状的画板.小A 拿出了p 支不同颜色的画笔,开始在上面涂色.看到小A 涂好的画板,小B 觉得颜色太单调了,于是把画板擦干净,希望涂上 ...

  3. 笔试算法题(48):简介 - A*搜索算法(A Star Search Algorithm)

    A*搜索算法(A Star Search Algorithm) A*算法主要用于在二维平面上寻找两个点之间的最短路径.在从起始点到目标点的过程中有很多个状态空间,DFS和BFS没有任何启发策略所以穷举 ...

  4. Python 迭代器-生成器-面向过程编程

    上节课复习:1. 函数的递归调用 在调用一个函数的过程中又直接或者间接地调用了函数本身称之为函数的递归 函数的递归调用有两个明确的阶段: 1. 回溯 一层一层地调用本身 注意: 1.每一次调用问题的规 ...

  5. 如何系统学习并且掌握JavaScript

  6. Zabbix微信告警

    Zabbix微信告警 摘要 Zabbix可以通过多种方式把告警信息发送到指定人,常用的有邮件,短信报警方式,但是越来越多的企业开始使用zabbix结合微信作为主要的告警方式,这样可以及时有效的把告警信 ...

  7. 空循环导致CPU使用率很高

    业务背景 业务背景就是需要将多张业务表中的数据增量同步到一张大宽表中,后台系统基于这张大宽表开展业务,所以就开发了一个数据同步工具,由中间件采集binlog消息到kafka里,然后我去消费,实现增量同 ...

  8. 洛谷 2187 小Z的笔记

    [题解] DP.  设f[i]表示前i个字母,保留第i个字母,最多可以保留多少个字母:设g[i]为当前字母为i的位置对应的f的最大值. 转移方程就是f[i]=max(f[i], g[j]+1) (j与 ...

  9. ASP.NET获取客户端IP及MAC地址

    朋友最近问如何获取客户端IP及MAC地址,一直想把这段给整理一下,契机来了:下边分为了C#后台获取的方法和前台Javascript(调用ActiveX)获取的方法,大家如果有好的方法一起讨论撒O(∩_ ...

  10. 洛谷 P2285 BZOJ 1207 [HNOI2004]打鼹鼠

    题目描述 鼹鼠是一种很喜欢挖洞的动物,但每过一定的时间,它还是喜欢把头探出到地面上来透透气的.根据这个特点阿牛编写了一个打鼹鼠的游戏:在一个n*n的网格中,在某些时刻鼹鼠会在某一个网格探出头来透透气. ...