创建一个松散耦合的&使用Core(Mediator)/ Sandbox(Facade)/模块模式的多页JS应用程序 - 建议?

时间:2012-10-31 02:02:44

标签: javascript module javascriptmvc

我正在构建一个多页面的javascript应用程序。我已经阅读了很多设计模式,并使用Core / Facade / Module方法创建应用程序w /松散耦合(pub / sub scribing to events)。

我有一个非常好的系统,可以缩小和缩小结合我的所有模块文件&在部署时将相关依赖关系转换为单个外部JavaScript文件。最小化我的应用程序的额外HTTP请求是一个设计目标 - 因此我对AMD(异步模块定义)不太感兴趣。

我正在使用Nicholas Zakas演讲中指出的指导方针, 可扩展的JavaScript应用程序架构

http://www.youtube.com/watch?v=vXjVFPosQHw

&安培;&安培;

Addy Osmani的大规模JavaScript应用程序架构模式 http://addyosmani.com/largescalejavascript/

&安培;&安培;

这个高级教程,来自Nettuts的Andrew Burgess,编写模块化JavaScript http://marketplace.tutsplus.com/item/writing-modular-javascript/128103/?ref=addyosmani&ref=addyosmani&clickthrough_id=90060087&redirect_back=true

我的问题是关于如何管理此应用程序的不同页面的建议&他们的相关模块。我还使用Backbonejs的Router类w / ballupton的History.js库来操作HTML5历史/状态API,并在不刷新的情况下动态加载页面,同时保持不支持HTML状态API的旧浏览器的向后兼容性。我的所有页面都共享一个公共代码库(单个缩小和压缩的js文件)。

以下是我想在我的应用程序中使用的结构概述: enter image description here

它本质上是一种混合方法。上半部分包含核心/外观/模块模式,其中包含不相互直接交互并通过外观发布/订阅通知的离散模块。

下半部分由我提出的应用程序结构组成,当状态/ url发生变化时通知“主控制器”,主控制器执行任何全局操作(如初始化我的UI的标题和侧边栏菜单,如果尚未初始化)并指示相关的子控件运行它的init()方法(以及在之前加载的任何控制器上调用destroy();)。每个子控制器(与ex:主页,日历页面,预订页面等相关)从可用模块池中挑选模块并初始化它们。

这是一个好方法还是我走上了糟糕的道路?我可以看到模块仍然彼此独立,这有利于可扩展性。

我还考虑过对待路由器和放大器。控制器作为离散模块并让它们发布/订阅Core,每个控制器以某种方式初始化它所需的模块页面。

2 个答案:

答案 0 :(得分:6)

我们为保持历史工作顺利进行的一件事是首先更改网址。在更改URL时会触发事件,路由器将解析该URL然后找出要执行的操作。此事件也会在页面加载时自动触发。如果单击一个链接,它只会更改URL,这非常简单,并且完全将链接/按钮与应用程序逻辑分离。这似乎适用于我们的应用程序。我们使用了JQM,但是由于我们从一些XML文件中读取了大部分指令并且没有一堆HTML页面加载到主视口区域,因此我们删除了大部分路由器。

我经常看到骨干应用程序使用路由器作为核心/中介。这是一个好主意。您只需监听URL的更改事件,然后适当地更改页面。虽然单身人士难以进行单元测试,但这个中间人可能应该是单身人士。

我不一定同意Backbone的观点是它对“观点”的定义。视图类似于控制器中的动作(从某些角度来看)。此时我们在应用程序中添加了一个更高级别的分离。我们的视图向模板文件发出了ajax请求,这些文件填充了一些JSON和handlebars.js。我会说你的标题/侧边栏应该只是模板。如果你需要刷新它们,那么看看你如何能够做到非常简单,否则你正在寻找创建4个新模块:列表集合,每个项目的模型,集合视图和模型视图。我将模板与更高级别的视图结合起来,直到需要进一步细分(例如,某些“应用程序/主视图”)。

拥有此模板层可以让您进行表面更改而无需重新编译,这很不错。任何时候你都可以把东西放到“元”中,这是一个胜利(除非它要求你阅读XML(ha))。作为奖励,您可以单独缓存模板(或者就此而言单独缓存它)。

您的架构似乎确实很好,并且是解决您问题的有效方法。我给出的一个提示是不要过度设计。迭代是最好的。你需要重构。无法预见什么会使您的应用程序提前3-6个月更流畅。

2013年12月18日更新

现在我们正在使用木偶和更多的奥斯玛尼技巧。除上述项目外,我们还使用了AMD的替代格式:

define(function(require) {
    var myTemplate = require('hb!mytemplate.handlebars'),
        view = require('myview');
    ...
});

我们还将marionette应用程序类与提供请求/响应层的wreqr结合使用。这允许我们干净地设置应用程序范围的对象。它还允许我们在没有明确声明类名的情况下定义类。这是一个非常好的沙盒方法。 EG:

this.app.setHandler('CanvasClass', function() {
    return RaphaelCanvasView;
});

// elsewhere

this.app.request('CanvasClass').text('123', {x:1, y:2});

这一切看起来都很顺利。

您还应该检查光环js和Web组件。我们的目录结构类似于模仿/预测这些概念而无需投资它们。

答案 1 :(得分:2)

我认为这是一个很好的方法。 我一直在开发类似于2个巨大的商业网络应用程序(减去主干,并使用自定义历史管理器),它的效果很好。我也没有使用AMD,所有交互都由pub / sub处理。 我最好的灵感之一(我相信你已经知道)是:https://github.com/aurajs/aura