模块化就是把系统分离成独立功能的方法,这样我们需要什么功能,就加载什么功能。
主要解决的问题:
- 命名冲突
- 文件依赖






代码学习:
define(function(require, exports, module) {var age = 30;var b = require('b.js');console.log(b.sex);exports.age = age;});
define(function(require, exports, module){var sex = '男';return {sex: sex};});
<script src="startUp.js"></script><script>startUp.use(['a.js', 'b.js'], function(a, b) {console.log(a);console.log(b);console.log('startUp...');});</script>
(function(global) {startUp = global.startUp = {version: '1.0.1'};var data = {};var cache = {};var anonymousMeta = {};var status = {FETCHED: 1, // 正在获取当前模块的uriSAVED: 2, // 在缓存中存储模块信息LOADING: 3, // 正在加载当前模块的依赖项LOADED: 4, // 准备执行当前模块EXECUTING: 5, // 正在执行单签模块EXECUTED: 6 // 执行完毕已经获取到接口对象};var isArray = function(obj){return toString.call(obj) === '[object Array]';};var isFunction = function(obj){return toString.call(obj) === '[object Function]';};var isString = function(obj) {return typeof obj === 'string';};// 是否使用了别名function parseAlias(id) {var alias = data.alias; //别名配置return alias && isString(alias[id]) ? alias[id] : id;}//不能以 "/" 或":"开头,结尾必须是一个“/”后面跟随任意字符至少一个var PATHS_RE = /^([^\/:]+)(\/.+)$/;// 是否使用了路径短名称function parsePaths(id) {var paths = data.paths;if(paths && (m = id.match(PATHS_RE)) && isString(paths[m[1]])) {id = paths[m[1]] + m[2];}return id;}// 检测是否添加后缀function normalize(path) {var last = path.length - 1;var lastC = path.charAt(last);return (lastC === '/' || path.substring(last-2) === '.js') ? path : path + '.js';}// 添加根目录function addBase(id, uri) {var result;if (id.charAt(0) === '.') {result = relapath((uri ? uri.match(/[^?]*\//)[0] : data.cwd) + id);}else {result = data.cwd + id;}return result;}var DOT_RE = /\/.\//g; // 规范路径 "/./" => "/"// 相对路径的处理function relapath(path) {path = path.replace(DOT_RE, '/');return path;}// 生成绝对路径startUp.resolve = function(child, parent){if (!child) {return '';}child = parseAlias(child); // 处理别名child = parsePaths(child); // 处理路径别名,路径短名称child = normalize(child); // 是否添加后缀return addBase(child, parent); // 添加根目录};//加载依赖项startUp.request = function(url, callback){var node = document.createElement('script');node.src = url;document.body.appendChild(node);node.onload = function() {// 移除script元素,不留加载痕迹//node.onload = null;//document.body.removeChild(node);callback();};};// Module 构造函数,模块初始化数据function Module(uri, deps){this.uri = uri;this.deps = deps || [];this.exports = null;this.status = 0;this._waitings = {};this._remain = 0;}//分析主干上的依赖项Module.prototype.load = function() {var module = this;module.status = status.LOADING;var uris = module.resolve();var len = module._remain = uris.length;// 加载主干上的依赖项var m;for (var i = 0; i < len; i++) {//创建缓存信息m = Module.get(uris[i]);if (m.status < status.LOADED) {m._waitings[module.uri] = m._waitings[module.uri] || 1;}else {module._remain--;}}// 如果依赖项列表全部加载完毕if (module._remain == 0) {module.onload();}//准备执行根目录下的依赖项列表中的模块var requestCache = {};for(var i = 0; i < len; i++) {// 获取依赖模块m = Module.get(uris[i]);if (m.status < status.FETCHED) {m.fetch(requestCache);}}for(uri in requestCache) {requestCache[uri]();}};// 加载依赖列表中的模块Module.prototype.fetch = function(requestCache){var module = this;module.status = status.FETCHED;var uri = module.uri;requestCache[uri] = sendRequest;function sendRequest() {startUp.request(uri, onRequest);}function onRequest() {if(anonymousMeta) {module.save(uri, anonymousMeta);}// 递归,模块加载策略module.load();}};Module.prototype.onload = function() {var mod = this;mod.status = status.LOADED;if (mod.callback) {mod.callback();}_waitings = mod._waitings;var uri, m;for (uri in _waitings) {//根目录对应的Module实例对象m = cache[uri];m._remain -= _waitings[uri];if(m._remain == 0) {m.onload();}}};// 更改初始化数据Module.prototype.save = function(uri, meta) {var module = Module.get(uri);module.id = uri;module.deps = meta.deps || [];module.factory = meta.factory;module.status = status.SAVED;};// 获取模块对外接口对象Module.prototype.exec = function(){var module = this;//防止重复执行if(module.status >= status.EXECUTING) {return module.exports;}module.status = status.EXECUTING;var uri = module.uri;function require(id) {// 更新过后的数据console.log(require.resolve(id));// 获取接口对象return Module.get(require.resolve(id)).exec();}require.resolve = function(id){return startUp.resolve(id, uri);};var factory = module.factory;var exports = isFunction(factory) ? factory(require, module.exports = {}, module) : factory;if(exports === undefined) {exports = module.exports;}module.exports = exports;module.status = status.EXECUTED;return exports;};//资源定位, 解析依赖项生成绝对路径Module.prototype.resolve = function(){var mod = this;var ids = mod.deps; // ['a.js','b.js'] => ['./a','./b']var uris = [];for(let i = 0; i < ids.length; i++) {uris[i] = startUp.resolve(ids[i], mod.uri);}return uris;};//定义一个模块Module.define = function(factory){var deps;if(isFunction(factory)) {// 正则解析依赖项deps = parseDependencies(factory.toString());}// 存储当前模块信息var meta = {id: "",uri: "",deps: deps,factory: factory};anonymousMeta = meta;}// 检测缓存对象上是否有当前模块的信息Module.get = function(uri, deps){return cache[uri] || (cache[uri] = new Module(uri, deps));};Module.use = function(deps, callback, uri){//获取模块var module = Module.get(uri, isArray(deps) ? deps : [deps]);// 所有模块都加载完毕module.callback = function(){// 所有依赖项模块的接口对象var exports = [];var uris = module.resolve();for (var i = 0; i < uris.length; i++) {exports[i] = cache[uris[i]].exec();}if (callback) {callback.apply(global, exports);}};module.load();};var _cid = 0;function cid(){return _cid++;}data.preload = [];//获取当前项目文档的uridata.cwd = document.URL.match(/[^?]*\//)[0];Module.preload = function(callback) {var length = data.preload.length;if (!length) {callback();}//length !== 0, 先加载预先设定模块};startUp.use = function(list, callback) {// 检测有没有预先加载的模块Module.preload(function() {Module.use(list, callback, data.cwd + '_use_' + cid()); //虚拟根目录});};var REQUIRE_RE = /\brequire\s*\(\s*(["'])(.+?)\1\s*\)/g;function parseDependencies(code) {var ret = [];code.replace(REQUIRE_RE, function(m, m1, m2){if(m2){ret.push(m2);}});return ret;}global.define = Module.define;})(this);
