Skip to content
New issue

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

Action的initBehavior事件疑问 #27

Closed
killeryyl opened this issue Mar 21, 2013 · 14 comments
Closed

Action的initBehavior事件疑问 #27

killeryyl opened this issue Mar 21, 2013 · 14 comments

Comments

@killeryyl
Copy link
Contributor

按理说这个initBehavior就类似与以前er框架的render操作。在之后的refresh里是不会再次触发的了。这个在loadSubAction里很有必要这么做。我这里马上就弄好book-store里loadSubAction的样例了,期间遇到了些,一会请你一起看看。

@otakustay
Copy link
Member

原则上,View就是一个东西,refresh等于View的重新渲染,但 并不会销毁并重新创建View ,因此通过initBehavior绑在View上面的事件都还在,不需要再次执行initBehavior。能再详细说说具体的案例吗?

@killeryyl
Copy link
Contributor Author

案例已经提交https://github.com/killeryyl/er/tree/master/example/book-store-subAction
主要是book/List.js里的initBehavior
“给Action自身绑定事件”
按你的说法这个initBehavior还是要的,引用以前的做法,可能会多出个refresh之类的东东

@otakustay
Copy link
Member

有几个疑问:

  1. 给自己绑定search事件的作用是……在哪里有调用该Action的fire('search')吗?
  2. 如果有地方要触发一个Action的事件,这个Action应该暴露一个方法,而非直接让人用fire。在 book/List 中,显然直接把search方法作为BookList.prototype.search即可,外面直接调用seach(query)
  3. 在怎么样的情况下,需要这个initBehavior再执行一次,能简单地把逻辑说一下吗,我这边光看代码似乎看不出入口在哪里……

谢谢

@killeryyl
Copy link
Contributor Author

情况是这样的,入口是book/Index文件
book/List作为它的subAction
在导航那里点击排序或者搜索关键字就会触发一次Index里的search方法,该方法触发subAction的serach事件。
有这样几个想法:
1.实现最基本的loadSubAction。并且subAction能和supAction相互交流,最好用事件方式交流会比较统一。
2.尝试给Action自身用on添加事件。但是这个只能在Action自身Enter之后或者说在new过之后才能用on的方法添加。prototype的添加在Index里用过了,这个是为了试试其他的方式。
3.每一次Action的enter执行都会产生新的model和view,对此用on的方式绑定是不会出现重复绑定的。但Action自身不会重生。demo里使用的subAction就是不消灭Action自身而再次enter进入,这样的话事件都会2次触发,若在其中绑定自身的on事件就会重复了。

@otakustay
Copy link
Member

说下我的看法:

首先,2个对象(我们不管这是Action还是View什么的,总之是2个对象)之间的交互有2条路:

  1. 方法调用
  2. 触发事件

但这2条路是有区别的,它们所负责的 逻辑流动方向 不同:

  1. 方法调用,是一个被动的过程,即对象 等着人来用我
  2. 触发事件,是一个主动的过程,即对象 主动告诉别人我在干啥

这2条路不应该混用,因此 给自己绑定事件 这样的逻辑实际上是一个不合理的设计,因为 自己随时都知道自己在干啥,不需要通知 。另一方面, 别人不应该触发我的事件 (除非我天生就是个消息总线,比如 er/events 模块) ,所以被它人调用fire方法同样是个不合理的设计。

所以希望不要纠结于用多种方法实现交互,ER框架的定位是一个 Solution Framework ,介于 解决方案框架之间 (这个是我的错没有更详细的文档来说明ER到底是个啥)。 解决方案 的特点是圈死所有的事情,让开发者完全按自己的模式来。 框架 的特点是提供基础的业务模型,让开发者在此之上构建抽象层和业务实现。 而 Solution Framework 介于两者之间,本身仅提供基础的业务模型,但在这个模型中,会出现 对业务实现的引导思想 ,使得业务实现时不会太过五花八门离题万里,这是我的目标。因此,ER一直以来都透露一个信息,即 对外通知用事件,外部命令用方法 ,如果没有非常明确的优势,没必要改掉这个理念。

因此:

  1. subAction和supAction的交互就是 supAction监听subAction的事件,必要的时候调用subAction的方法 ,我认为统一成事件破坏了事件本身的定位,并不是一个好现象。
  2. 基于此,Action不需要给自身添加事件。如果真要,在构造函数中就能加,没必要硬等到initBehavior来。
  3. 我看到从onentercompleteloadSubAction,这个 book/List 是每次都会被new出来,走一个完整的生命周期的,放在me.subAction中的东西也没有重用的迹象,似乎不存在多次绑定事件的问题?

@otakustay
Copy link
Member

我明天会出一个renderChildAction的初步实现,到时候我们一起比对参考下,再定个最终的方案吧~

@killeryyl
Copy link
Contributor Author

回答下最后onentercomplete:这个是supAction生命周期的事,只触发一次,也就是说loadSubAction也只触发一次。subAction被存起来了。至于subAction的自身刷新是在search里调用enter方法,让其进入生命周期的,但这个使用不会正真结束其生命,subAction还是存在于supAction对象里。

@otakustay
Copy link
Member

search中的me.enter()似乎更应该倾向于使用me.view.render(model.valueOf()),现在的View.prototype.render不接受参数,导致这里搞起来麻烦,我打算让View.prototype.render接受一个model参数,如果不传就用this.model,传了就覆盖this.model,这样的话你的search()里还需要走Action的生命周期吗?

因为从我的角度来看,改了参数,不就是视图刷新嘛,Action管的业务逻辑似乎没必要再重新来一下……

@killeryyl
Copy link
Contributor Author

enter()这里走了一遍model的数据获取流程。enter里传进去的context参数相当于url里qurey的那串东东。所以光对view进行render是不够的。

@killeryyl
Copy link
Contributor Author

退一步其实可以这么理解,如果#book-list是个iframe的话,那supAction里操作subAction就简化成了修改iframe的src,变更里面的query参数,走一遍Action,包括根据最新参数获取相应的数据,然后渲染视图,绑定事件。

@otakustay
Copy link
Member

如果相当于修改src的话,为何要缓存subAction并重复调用enter()呢?当修改了src之后,<iframe>会重新创建window对象,加载页面,解析文档等,是不是应该相当于重建了一个Action,所以应该每次都new一个出来……

简单来说,就是我认为修改src这一行为,对应的应该是loadSub方法,而不是Action的enter方法。

如果切实地,缓存一个Action对象这样做有很大的收益,我们再看看这样的功能是应该由Action基类提供,还是说这是具体有业务需要时,这个Action作为个体提供类似refresh方法的。但总之我认为enter()是不应该被调用多次的,enterleave应该成对出现,要调用enter()至少也要先leave()一次,但Action的设计理念不是给人这么用的,不然也不会把Action做成可以实例化的类,保持0.8版本的Action是个对象,用完了自己手工清理下,下次复用的思路就行。但事实是这种复用的思路带来了很多的麻烦

@killeryyl
Copy link
Contributor Author

嗯,我这个复用确实看着不对劲。缓存Action对象的至少能保证父级Action能方便地使用子级Action的方法等。
demo里,Index中的search方法就是这么办的。当然,为了避免enter的重复非成对使用,search方法应该改为和complete里同样的操作,即loadSubAction,并把search的参数传递进去。
但这样弄的话问题就来了,subAction里的存有的上下文有些可能还是有用的,有些要删掉,有些要新增或修改。
在book/List里我是这么弄的
me.model.set(query);//先改改删删,留下有用的
me.enter(me.model.valueOf());//保证原有数据能存进新的mode里,view能按此数据正常显示
整个过程subAction不需要重新再来,也就不存在着leave的需要。(上面谈起iframe其实就是想简单的表明loadSubAction也是需要类似的URLQuery参数,这个Action可以单独显示在浏览器里作为单测。仅supAction调用的时候赋予特别的container及部分私有的交互方法,subAction自身定义公共的交互方法);
如果这里有refresh的方式,也就是仅单向的执行enter里的流程,不触发leave,这样对理解起来比较好。

@otakustay
Copy link
Member

我做了一个controller.renderChildAction的功能,在 example/book-store/src/book/List.js 中可以看到相关的调用。

设计上,我的追求是 透明化 ,即一个Action基本不需要关心自己是主Action还是子Action,比如其中链接点击的跳转、编码的跳转(统一用this.redirect)都做了处理,参见controller里的enterChildAction这个函数。

交互上我还没写足够的示例(这一块没啥好交互的),但交互的方式都是成立的,有注册子Action的leave事件(其实这个写法不太好,因为一但子Action再有跳转,leave一触发,容器就没了会出错,在此仅为了演示),其它的交互也可以使用同样的方法,注册事件,调用方法。

但子Action,默认情况下框架是不管理的,需要统一处理,而且Action的加载是异步的( @killeryyl 给的方案是同步的,事实上不是太合适),所以加载有个过程,如何控制并行的加载相互冲突等问题,也由调用者管理(在 book/List 中有实现,调用cancel()那一段)。

我们再相互参考下,看看有什么不足需要弥补的~请 @DDDBear 也一起来讨论下

@killeryyl
Copy link
Contributor Author

在renderChildAction中已经重制了action.redirect功能,这个可以疑问得以解决,可以消除。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants