原文地址:http://chaoskeh.com/blog/why-seajs.html

Why SeaJS

前言

本文主要面向刚接触 SeaJS 的同学。
文章会先提出传统 Javascript 开发上遇到的一些难以解决的问题(即“冲突”与“依赖”两节),然后介绍如何使用 SeaJS 来解决这些难点(即 “Why SeaJS” 一节)。
实际上,如果你想了解 RequireJS 等其他模块加载器,也可以阅读本文

冲突

我们从一个最简单的例子开始
以前我做项目时,常常会将一些通用的、底层的功能抽出来,独立成一个函数,比如

function print(str) {
// 代码!
};

然后像模像样的将这个函数丢到 util.js 里面,最后告诉大家:你们想用 xx 功能时候,引入 util.js 就行啦
这是一个很好的习惯(嘻嘻),但是项目做久了,难免会遇到问题,比如常有人问我:

  • 你这个函数为啥叫 print 啊!正好我也刚写了个函数叫 print 啊!要不我改名叫 print2 吧!(我靠……)
  • 你这个函数为啥叫 print 啊!我引入了个开源的模块,里面也有个函数叫 print 啊!改人家的怕有问题,要不改你的吧!(我再靠……)

在没有命名空间的 Javascript 中,发生这样的情况一点都不奇怪,幸亏有补救方案,可以用对象模拟命名空间

var FocusTech = {};
FocusTech.print = function(str){
// 代码!
}

这样需要调用这个函数时,得带上命名空间 FocusTech.print(‘我是字符串啊’) 
虽然麻烦一点,不过能降低函数命名冲突的概率,可惜也只是降低而已
比如这里我选择了用公司名字作为命名空间,但是我们公司几百号研发人员,跟我一样想法的人肯定大有人在
所以命名空间依然有可能会冲突。那么为了继续降低冲突概率,只好拉长命名空间,比如学 Java 用项目的网址做命名空间
下面这段代码节选自 Yahoo! 的一个开源项目

if (org.cometd.Utils.isString(response)) {
return org.cometd.JSON.fromJSON(response);
}
if (org.cometd.Utils.isArray(response)) {
return response;
}

看到这里我其实还是挺同情他们的,为了避免冲突用了那么长一个命名空间,对记忆和书写的负担实在太重了
好了,冲突的问题暂且放着,我们继续往下看

依赖

继续讲简单的例子,我开始编写一个通用的展示组件,提供给项目组使用,这样其他同学就不用重复造轮子了
我告诉大家:组件写在 componet_one.js 中,你们要用的时候引入一下就行啦
于是另一位同学就这么做了:

<script src="componet_one.js"></script>
<script>
FocusTech.ComponetOne.init();
// 代码!
</script>

看上去很好,可是报错了!
我赶紧查找原因,发现原来是我的组件中,调用了上面一个例子中提供的 print 方法,而页面中没有引入 util.js ,赶紧加上!

<script src="util.js"></script>
<script src="componet_one.js"></script>

很快就修复了,看上去好像挺简单的,不过让我们看看这个例子的后续发展:

  • 某天,我扩充了组件的功能,除了需要 util.js 之外,还需要 ooxx.js

这时候,项目中已经有 N 个地方用到了我的组件……
于是我只好全局搜索每一个调用的地方,都给页面加上对 ooxx.js 的引用

  • 某天,需求砍掉了组件上的一个交互效果

我修改了 componet_one.js 的代码,然后发现我不再需要 util.js 中提供的 print 方法了
于是我再次全局搜索每一个调用的地方,去掉对 util.js 的引用

  • 测试同学告诉我,改完之后,好多个页面报错!

我赶紧检查,发现有些页面上是这样的

<script src="ooxx.js"></script>
<script src="componet_one.js"></script>
<script src="componet_two.js"></script>

页面还引入了 componet_two.js ,而且 componet_two.js 中用到了 util.js 的 print 方法!
所以 BUG 原因找到了,我不能武断地把 util.js 全都去掉,而是需要仔细检查页面上的其他的 JS 文件或代码是否需要它!
崩溃……

  • 一段时间后,测试同学又来找我,说页面又报错了!

再次检查,发现原来是某人动过了 ooxx.js ,在里面调用了 util.js 的方法……害死人不偿命啊!
好吧,我只好再次全局搜索所有使用到 componet_one 组件的地方,给页面加上 util.js 的引用

小结

我已经不忍心再讲下去了,正所谓:看到哪句你哭了,不顶不是中国人!
相信做过大一点项目的同学,应该都遇到过上面的这种破事。
为什么会这么费神呢?因为 javascript 的语法中天生缺少引入其他 JS 文件的语法。
相比之下,我们的好战友设计师们就轻松很多了,比如:

@import url("base.css");

#test {...}
.classA {...}
.classB {...}

看到吧,人家只要用一个 @import 就解决了,页面中引入 css 时,只需要引入这个 css ,浏览器会自动去下载 base.css
css 文件的依赖能够实现自动管理,而不是像 js 一样,需要手动地去编写

OK,下面终于可以进入重点了

Why SeaJS

先不谈理论,直接来看看上面的这两个例子中如果引入 SeaJS 该怎么写
首先是 util.js ,我们改用 SeaJS 的 CMD 规范来书写

define(function (require, exports) {
function print(str) {
// ...代码
} exports.print = print;
});

可以看到,其实改变并不大,主要是外部包裹了一层,再加最后多写了一行
最后这行很重要,通过它,文件对外提供一个叫做 print 方法的接口
另外大家发现没,这里我没有使用命名空间,为什么呢?看下面的 componet_one.js

define(function (require, exports) {
var util = require('./util.js'); var ComponetOne = {
doSth : function() {
util.print('我是字符串');
// ...代码
}
} return ComponetOne;
});

高潮终于到了!
首先是 var util = require('./util.js'); 这句,有没有觉得很熟悉?是不是很像上面提到的 @import url("base.css"); ?
没错!这里的 require 可以认为是 SeaJS 给 Javascript 增加的一个关键词语法,就像 @import 这个关键词一样!

通过这个函数,SeaJS 赋予了 Javascript 直接加载 js 文件的功能,并且这个函数是 同步 的!
函数直接就有一个返回值,那么返回值是什么呢?相信你已经猜到了,就是 util.js 里面的 exports 对象
所以下面我们就可以使用 util.print() 来调用 util.js 提供的对外接口了

刚才那个问题有答案了:因为 require 函数的返回值赋值给哪个变量完全由 componet_one 决定,变量名可以随便起,与 util.js 毫无关系(这里为了方便变量也叫 util ),所以 util.js 里面自然就不需要命名空间了!

那么页面中该怎么引入呢?很简单

<script src="sea.js"></script>
<script>
seajs.use('./componet_one.js')
</script>

我们需要先引入 SeaJS 这个加载器,然后通过它提供的 API 来加载文件
而且最重要的是:因为有了 require ,这里我们只需要加载 componet_one.js 即可,util.js 会由 SeaJS 自动加载!
也就是说,因为有了 require ,我们获得了类似 css 的文件依赖自动管理机制!

小结

仔细琢磨一下这几行代码,我想大家应该能看出 SeaJS 带给 Javascript 开发的巨大好处:

  • 一般来说,不再需要冗长的命名空间了,也不再需要担心命名的冲突
  • 不需要手动管理 js 文件的依赖,依赖关系写在代码中,SeaJS 会自动处理

别小看这两点,对于稍微有些规模的项目来说它们非常重要,我想这也是 SeaJS 备受青睐的原因。
最后,SeaJS 的 CMD 规范非常简单易懂,SeaJS 的 API 也非常简洁优雅,相信有一定开发经验的同学很快就能上手
更多信息可以移步 SeaJS官网

转:Why SeaJS的更多相关文章

  1. seaJs学习笔记2 – seaJs组建库的使用

    原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...

  2. 初学seaJs模块化开发,利用grunt打包,减少http请求

    原文地址:初学seaJs模块化开发,利用grunt打包,减少http请求 未压缩合并的演示地址:demo2 学习seaJs的模块化开发,适合对seajs基础有所了解的同学看,目录结构 js — —di ...

  3. JS模块化开发:使用SeaJs高效构建页面

    一.扯淡部分 很久很久以前,也就是刚开始接触前端的那会儿,脑袋里压根没有什么架构.重构.性能这些概念,天真地以为前端===好看的页面,甚至把js都划分到除了用来写一些美美的特效别无它用的阴暗角落里,就 ...

  4. seajs的使用

    写在前面 seajs是什么? Seajs是一个js文件加载器. 遵循 CMD 规范模块化开发,依赖的自动加载.配置的简洁清晰. 用于Web开发的模块加载工具,提供简单.极致的模块化体验 一:使用 文件 ...

  5. 用spm2构建seajs项目的过程

    前言 Javascript模块化规范有CommonJs规范,和主要适用于浏览器环境的AMD规范,以及国内的CMD规范,它是SeaJs遵循的模块化规范.因为以前项目中用SeaJs做过前端的模块管理工具, ...

  6. jquery插件封装成seajs模块

    jquery直接在html中引入. jquery插件修改为: define(function (require, exports, moudles) { return function (jquery ...

  7. 快速上手seajs——简单易用Seajs

    快速上手seajs——简单易用Seajs   原文  http://www.cnblogs.com/xjchenhao/p/4021775.html 主题 SeaJS 简易手册 http://yslo ...

  8. seajs学习一天后的总结归纳

    公司项目最近需要将js文件迁移到seajs来进行模块化管理,由于我以前主要接触模块化开发是接触的AMD规范的requireJS,没有接触过CMD规范,而且在实际项目中还没有用过类似技术.于是,我非常兴 ...

  9. RequireJS与SeaJS模块化加载示例

    web应用越变的庞大,模块化越显得重要,尤其Nodejs的流行,Javascript不限用于浏览器,还用于后台或其他场景时,没有Class,没有 Package的Javascript语言变得难以管理, ...

  10. 新手 gulp+ seajs 小demo

    首先,不说废话,它的介绍和作者就不在多说了,网上一百度一大堆: 我在这里只是来写写我这2天抽空对seajs的了解并爬过的坑,和实现的一个小demo(纯属为了实现,高手请绕道); 一.环境工具及安装 1 ...

随机推荐

  1. iOS-NSURLCache内存缓存

    在IOS应用程序开发中,为了减少与服务端的交互次数,加快用户的响应速度,一般都会在IOS设备中加一个缓存的机制.使用缓存的目的是为了使用的应用程序能更快速的响应用户输入,是程序高效的运行.有时候我们需 ...

  2. GET请求和POST请求简单说明

    一.概述 * HTTP/1.1协议共定义了8中请求方法:OPTIONS, HEAD, GET, POST, PUT, DELETE, TRACE, CONNECT. * GET方法和POST是我们使用 ...

  3. Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面

    Android应用的开发过程中需要把繁重的任务(IO,网络连接等)放到其他线程中异步执行,达到不阻塞UI的效果. 下面将由浅入深介绍Android进行异步处理的实现方法和系统底层的实现原理. 本文介绍 ...

  4. The u32 classifier

    The u32 classifier The U32 filter is the most advanced filter available in the current implementatio ...

  5. openvswitch——mac和vlan learning for ingress port

    对于普通的switch,都会有这个学习的过程,当一个包到来的时候,由于包里面有MAC,VLAN Tag,以及从哪个口进来的这个信息.于是switch学习后,维护了一个表格port –> MAC ...

  6. html5实现饼图和线图-我们到底能走多远系列(34)

    我们到底能走多远系列(34) 扯淡: 送给各位一段话:     人生是一个不断做加法的过程     从赤条条无牵无挂的来     到学会荣辱羞耻 礼仪规范     再到赚取世间的名声 财富 地位    ...

  7. c#实现高精度四舍五入

    /// <summary>        /// 實現數據的四捨五入        /// </summary>        /// <param name=" ...

  8. SQL编写

    //用户表,用户ID,用户名称create table t_user (user_id int,username varchar(20));//用户帐户表,用户ID,用户余额(单位分)create t ...

  9. C特殊浮点值NaN

    特殊浮点值NaN(Not-a-Number),例如asin()函数返回反正弦值,所以输入参数不能大于1,否则函数返回NaN值,printf()显示为nan,NaN或类似形式.

  10. JS的跨域问题

    1.什么是跨域? 跨域问题是由于javascript语言安全限制中的同源策略造成的. 2.什么是同源策略: 同源策略是指一段脚本只能读取来自同一来源的窗口和文档的属性,这里的同一来源指的是主机名.协议 ...