世面上有好多JavaScript的加载器,比如 sea.js, require.js, yui loader, labJs…., 加载器的使用范围是一些比较大的项目, 个人感觉如果是小项目的话可以不用, 我用过seaJS和requireJS, 在项目中用过requireJS, requireJS是符合AMD,全称是(Asynchronous Module Definition)即异步模块加载机制 , seaJS是符合CMD规范的加载器。
AMD__和__CMD
AMD规范是依赖前置, CMD规范是依赖后置, AMD规范的加载器会把所有的JS中的依赖前置执行。 CMD是懒加载, 如果JS需要这个模块就加载, 否则就不加载, 导致的问题是符合AMD规范的加载器(requireJS), 可能第一次加载的时间会比较久, 因为他把所有依赖的JS全部一次性下载下来;
常识,jQuery是支持AMD规范,并不支持CMD规范,也就是说, 如果引入的是seaJS,想要使用jQuery,要用alias配置, 或者直接把 http://www.php.cn/ 直接引入页面中;
//这是jQuery源码的最后几行, jQuery到了1.7才支持模块化;
// Register as a named AMD module, since jQuery can be concatenated with other
// files that may use define, but not via a proper concatenation script that
// understands anonymous AMD modules. A named AMD is safest and most robust
// way to register. Lowercase jquery is used because AMD module names are
// derived from file names, and jQuery is normally delivered in a lowercase
// file name. Do this after creating the global so that if an AMD module wants
// to call noConflict to hide this version of jQuery, it will work.
// Note that for maximum portability, libraries that are not jQuery should
// declare themselves as anonymous modules, and avoid setting a global if an
// AMD loader is present. jQuery is a special case. For more information, see
// http://www.php.cn/
if ( typeof define === "function" && define.amd ) {
define( "jquery", [], function() {
return jQuery;
});
};使用方法
比如我们可以这样定义一个模块:
立即学习“Java免费学习笔记(深入)”;
//文件所在的路径地址为:http://www.php.cn/:63342/module/script/dir2/1.js
define(function() {
return "!!!!";
});也可以这样定义一个模块:
//这个文件的路径为http://www.php.cn/:63342/module/main.js ,
而且有一个依赖, 加载器会自动去加载这个依赖, 当依赖加载完毕以后, 会把这个依赖(就是script/dir2/1.js)执行的返回值作为这个函数的参数传进去;
require(["script/dir2/1.js"], function(module1) {
console.log(module1);
});
//实际上会打印出 "!!!!"一般来说,一个模块只能写一个define函数, define函数的传参主要有两种方式:
1:正常上可以是一个函数;
2:可以是一个数组类型依赖的列表, 和一个函数;
如果一个模块写了多个define会导致模块失灵, 先定义的模块被后定义的模块给覆盖了 ( 当然了, 一般我们不那样玩);
一个模块内可以写多个require, 我们可以直接理解require为匿名的define模块, 一个define模块内可以有多个require, 而且require过的模块会被缓存起来, 这个缓存的变量一般是在闭包内, 而且名字多数叫modules什么的…..;
我们通过加载器开发实现的模块化开发要遵守一种规范, 规范了一个模块为一个JS,那么我们就可以新建几个目录为conroller,view, model, 也是为了后期更好的维护和解耦:

2010.09.03更新优化前台内核处理代码;优化后台内核、静态生成相关代码,生成速度全面提升;修改前台静态模板中所有已知错误;修正后台相关模块所有已知错误;更换后台编辑器,功能更强大;增加系统说明书。免费下载、免费使用、完全无限制。完全免费拥有:应广大用户要求,千博网络全面超值发布企业网站系统个人版程序包:内含Flash动画源码、Access数据库程序包、SQL数据库程序包。全站模块化操作,静态
实现一个自己的加载器
使用的方式:
//这个模块依赖的四个模块,加载器会分别去加载这四个模块;
define(["依赖0","依赖1","依赖2","依赖3"], function(依赖0,依赖1,依赖2,依赖3){
});
//返回一个空对象
define(function(){
return {};
});
//直接把require当作是define来用就好了;
require(["依赖0","依赖1","依赖2","依赖3"], function(依赖0,依赖1,依赖2,依赖3) {
//执行依赖0;
依赖0(依赖1,依赖2,依赖3);
});
//这个加载器define函数和require函数的区别是,define我们可以传个name作为第一参数, 这个参数就是模块的名字, 好吧, 不管这些了.....;以下为加载器的结构,因为代码量已经很少了, 所以每一函数都是必须的, 为了不影响全局, 把代码放在匿名自执行函数内部:
(function() {
定义一个局部的difine;
var define;
//我偷偷加了个全局变量,好调试啊;
window.modules = {
};
//通过一个名字获取绝对路径比如传"xx.js"会变成"http://www.mm.com/"+ baseUrl + "xx.html";
var getUrl = function(src) {};
//动态加载js的模块;
var loadScript = function(src) {};
//获取根路径的方法, 一般来说我们可以通过config.baseUrl配置这个路径;
var getBasePath = function() {};
//获取当前正在加载的script标签DOM节点;
var getCurrentNode = function() {};
//获取当前script标签的绝对src地址;
var getCurrentPath = function() {};
//加载define或者require中的依赖, 封装了loadScript方法;
var loadDpt = function(module) {};
//这个是主要模块, 完成了加载依赖, 检测依赖等比较重要的逻辑
var checkDps = function() {};
定义了define这个方法
define = function(deps, fn, name) {};
window.define = define;
//require是封装了define的方法, 就是多传了一个参数而已;
window.require = function() {
//如果是require的话那么模块的名字就是一个不重复的名字,避免和define重名;
window.define.apply([], Array.prototype.slice.call(arguments).concat( "module|"+setTimeout(function() {},0) ));
};
});加载器源码实现(兼容,chrome, FF, IE6 ==>> IE11), IE11没有了readyState属性, 也没有currentScript属性,坑爹啊, 无法获取当前正在执行的JS路径, 所以要用hack;
从叶大大那边偷的一个加载器, 这个加载器有点像jQuery中延迟对象($.Deferred)有关的方法when($.when)的实现;
一个例子
写一个MVC的小例子,代码简单, 高手无视, 目录结构如下:

我们把所有的事件放到了controller/mainController.js里面,
define(["model/data","view/view0"],function(data, view) {
var init = function() {
var body = document.getElementsByTagName("body")[0];
var aBtn = document.getElementsByTagName("button");
for(var i=0; i< aBtn.length; i++) {
aBtn[i].onclick = (function(i) {
return function() {
body.appendChild( view.getView(data[i]) );
};
})(i);
};
};
return {
init : init
};
});把所有的数据放到了model/data.js里面;
define(function() {
return [
{name : "qihao"},
{name : "nono"},
{name : "hehe"},
{name : "gege"}
];
})视图的JS放到了view的目录下,view0.js主要负责生成HTML字符串或者DOM节点;
define(function() {
return {
getView : function(data) {
var frag = document.createDocumentFragment();
frag.appendChild( document.createTextNode( data.name + " ") );
return frag;
}
}
});入口是app.js,他和load.html是同级目录:
require(["controller/mainController"],function( controller ) {
controller.init();
});load.html这个是主界面:
以上就是JavaScript 模块化编程之加载器原理详解的内容,更多相关内容请关注PHP中文网(www.php.cn)!









