构建具有伸缩性的JavaScript应用程序
多人协同构建一个大型的Web应用程序是一件困难的事。很多大型的Web应用程序开发到最后变得越来越头疼,很大一部分原因是由于JavaScript的架构设计的不清晰以及不具备高扩展性。在日常的工作中寻找一些trick以及一些tip只能解决特定问题,而不能让你的架构具有伸缩性。
将应用程序分解为多个层次,规定每层特定角色以及责任,让应用程序保持松耦合,这样的话,特定层接口被删除,修改或者替换的话对其它层的影响都是最小的。
整个应用程序架构应该由以下几个部分组成:
- Module
- Sandbox
- Core
- Base
我们可以在已有的JavaScript框架(jQuery, Dojo等)基础上构建我们的应用程序框架。重要的一点就是把每一个页面理解成一个Module(整个web应用程序的每一个独立功能模块)。我们构建的程序不可能只有一个页面,所以会产生多个Module。所有Module都应该仅仅依赖于它们自己,目的是为了松耦合。每一个Module都应该有自己的Sandbox, Sandbox是位于应用程序核心部分(Core)的上一层。Module应该知道Sandbox,但是Module彼此之间不用关心。
具有伸缩性的Web架构的每一个部分就类似于Puzzle游戏中的每一个Piece一样。每一个Piece不需要知道整个Puzzle有多复杂,它只要知道自己应该做什么就OK了。下面简要介绍一下每一个部分。
Module
Module的任务就是处理GUI与用户的交互,以及增强用户体验。这部分代码主要由JavaScript, HTML,以及CSS构成。其实整个Web应用程序就是由这些Module组合在一起工作的。
下面是一个Module的定义样例:
Core.register("module-name", function(sandbox){
return {
init: function(){
//构造函数
},
destroy: function(){
//销毁函数
}
};
});
Module主要关注以下几个方面:
- 只能调用Module内部的方法,或者Sandbox中的方法。
- 不要访问不是本地化的全局对象。
- 不要访问超出此Module管理的Box之外的DOM元素。
- 如果有需要访问别的什么东西的,只能调用Sandbox接口。
- 不要创建全局对象。
- 不要直接引用其他Module属性和方法。
Sandbox
Sandbox是用来确保接口的一致性,因为每一个Module都了解Sandbox。 你可能不想直接通过Module来设置cookies,就交给Sandbox。由于Sandbox定义完后修改比较困难,所以应该慎重设计Sandbox。下面是一个Sandbox使用样例:
Core.register("module-name", function(sandbox){
return {
init: function(){
//这里去调用Sandbox接口
if (sandbox.enableFire()){
alert("Fire…");
}
},
destroy: function(){
//销毁函数
}
};
});
Sandbox主要关注以下几个方面:
- 提供一致性接口。
- 确保安全。比如限制应用程序中的哪些Module能访问Sandbox,哪些不能。
- 提供通信。作为桥梁把Module的一些请求发送给Core的接口。
Core
Core就是应用程序的核心部分了,它主要用来控制应用程序。它用来初始化Module以及销毁Module。Core用来控制Module之间的通信,一个Module的状态改变后,就需要Core通知其它与之相关的Module。创建完Module后通知Sandbox状态发生改变是一个比较好的方法。因为Sandbox能够选择是否执行Module的请求。Core也应该包含错误异常捕捉模块。
下面是Core中控制Module部分的定义样例:
Core = function () {
var moduleData = {};
return {
register: function (moduleId, creator) {
moduleData[moduleId] = {
creator: creator,
instance: null
};
},
start: function (moduleId) {
moduleData[moduleId].instance =
moduleData[moduleId].creator(new Sandbox(this));
moduleData[moduleId].instance.init();
},
stop: function (moduleId) {
var data = moduleData[moduleId];
if (data.instance) {
data.instance.destroy();
data.instance = null;
}
}
}
} ();
下面是Core中关于Sandbox的控制:
Core = function(){
return {
//.....
startAll: function(){
for (var moduleId in moduleData){
if (moduleData.hasOwnProperty(moduleId)){
this.start(moduleId);
};
}
},
stopAll: function(){
for (var moduleId in moduleData){
if (moduleData.hasOwnProperty(moduleId)){
this.stop(moduleId);
}
}
},
//....
};
}();
注册Module应该:
Core.register("module1", function(sandbox){ /*...*/ });
Core.register("module2", function(sandbox){ /*...*/ });
启动所有Module:
Core.startAll();
Core 主要关注以下几个方面:
- 管理Module生命周期。
- 使得松耦合Module之间能够通信。
- 处理错误异常。
- 还要具有可扩展性
可扩展性是非常重要的,因为在某些场景下可能需要添加一些错误处理,AJAX通信,新Module的兼容以及一些工具库。
Base
Core直接与Base库交互,这样的话,Base库可以调换成任何JavaScript库。
Base主要负责以下几个方面:
- 浏览器标准化(消除同一接口在不同浏览器产生不同表现)。
- 封装一些通用的工具方法。例如解析/序列化XML,JSON,对象操作,DOM操作,AJAX通信等等。
- 提供低层次扩展
这样的Web架构其实可以在多个Web应用中重用的,同时每一个Module也适合单独测试和使用,针对不同的应用只要修改Module的接口实现。获益最大的应该是构建这样架构的Web应用应该是具有高扩展性的,可以在任何时候添加删除Module。
下一篇将使用此构架构建一个Demo应用程序。