atm-command-generate
Version:
atm-command-generate
315 lines (292 loc) • 9.71 kB
JavaScript
var define = null;
var atmjs = {};
(function (win) {
var loaderNode = document.getElementById('atmjsnode'), // atmjs加载器的script节点
baseUrl = loaderNode.getAttribute('data-base'), // 静态资源路径前缀
config = loaderNode.getAttribute('data-config'), // 异步数据配置
uriList = {}, // 文件id对应的文件全路径
list = {},
needs = {}, // require.use || require.async 加载的id数组
modules = {}, // 存放执行过后的模块接口数据
cssExists = {},// {cssFileId1: 1, cssFileId2: 1},
asyncQueues = [],
atmLoader = atmjs.loader = {
baseUrl: baseUrl,
uriList: uriList,
// undefined 尚未加载
// 10 加载中
// 20 加载成功且依赖正在加载中
// 30 加载成功且依赖已全部执行成功
// 40 自身执行完成
// 50 加载失败
modules: modules,
needs: needs,
list: list,
asyncQueues: asyncQueues,
asyncDeps: {},
cssExists: cssExists
};
function useOrAsync(timeout) {
function cb(ids, factory) {
ids = getIds(ids);
var deps = arrToObj(ids);
addNeeds(ids);
asyncQueues.push({
deps: deps,
factory: factory
});
// 如果所依赖的模块还有未执行的
if (!getStatus(deps)) {
for (var id in deps) {
//尝试执行所依赖的模块
tryExecModule(id);
}
} else {
// 执行异步队列
execAsync();
}
}
return function (ids, factory) {
if (timeout) {
setTimeout(function () {
cb(ids, factory);
}, 0);
} else {
cb(ids, factory);
}
};
}
atmjs.use = useOrAsync(false);
require.async = useOrAsync(true);
// define(id, dependencies?, factory)
define = function (id, depsArr, factory) {
if (typeof depsArr === 'function') {
factory = depsArr;
depsArr = [];
}
var deps = arrToObj(depsArr);
// 如果该文件之前的状态为 未加载或正在加载中 ,则改变status为20,说明该文件已经加载成功
if (!list[id] || list[id].status === 10) {
list[id] = {
id: id,
status: 20,
factory: factory,
deps: deps
};
// 如果该文件在needs列表里面,则尝试执行该文件
if (needs[id]) {
tryExecModule(id);
}
}
};
function execModule(id) {
if (!needs[id]) {
return;
}
//执行factory
var factory = list[id].factory;
var module = modules[id] = {
exports: {}
};
var ret = typeof factory === 'function'
? factory.apply(win, [require, module.exports, module])
: factory;
if (typeof ret !== 'undefined'){
module.exports = ret;
}
list[id].status = 40;
execAsync();
for (var i in list){
if (list[i].deps[id] && list[i].status === 20){
var deps = list[i].deps;
if (getStatus(deps)){
execModule(i);
}
}
}
}
function tryExecModule(id) {
// 如果还没有该id对应的信息,则找到该id对应的url去加载,同时在list中设置该id的status为10,说明该id已开始加载
if (!list[id]){
//
needs[id] = 1;
// 如果该id文件依赖css,则首先去加载所依赖的css文件
if (atmLoader.asyncDeps[id]) {
var arr = atmLoader.asyncDeps[id];
addCss(arr);
}
var uri = getUri(id);
if(!uri){
throw new Error('无法找到['+id+']对应的路径');
}
createScript(uri);
list[id] = {
status: 10,
deps: {}
};
} else if (list[id].status === 20) { // 如果该id文件已加载成功
var deps = list[id].deps;
// 判断依赖是否全部执行完成,如果依赖全部执行完成,则改变id在list中的status值为30
if (getStatus(deps)) {
execModule(id);
} else {
// 如果有依赖没有执行,则执行依赖
for (var i in deps) {
needs[i] = 1;
tryExecModule(i);
}
}
}
}
//atmjs.use&require.async内部调用的函数
function execAsync() {
// 如果异步队列为空,则跳出
if (!asyncQueues.length) {
return;
}
// 找出依赖都执行完毕的项
var arr = [];
for (var i in asyncQueues) {
if (getStatus(asyncQueues[i].deps)) {
arr.push(asyncQueues.splice(i, 1)[0]);
}
}
if (!arr.length) {
return;
}
for (var i in arr) {
var obj = arr[i],
factory = obj.factory;
if (typeof factory === 'function') {
var deps = getIds(obj.deps),
mods = [];
for (var id in deps) {
mods.push(modules[id].exports);
}
factory.apply(win, mods);
}
}
execAsync();
}
function setConfig(cfg) {
//var cfg = { // 加载&解析器用到的配置数据
// async: { // async数据
// alias: { // id与uri的对应关系
// id1: 'uri1',
// id2: 'uri2'
// },
// deps: { // js文件id依赖的cssid数组
// jsid1: ['depend css id1', 'depend css id2', 'depend css idN'],
// jsid2: ['depend css id1', 'depend css id2', 'depend css idN']
// },
// exists: { // 页面中已经存在的css文件的id,用于ajax创建css标签时的判断
// cssid1: 1,
// cssid2: 1
// }
// }
// // other to be set by user
//};
cfg = cfg || {};
var asyncConfig = cfg.async || {};
var alias = asyncConfig.alias || {};
var asyncDeps = asyncConfig.deps || {};
var cssExists = asyncConfig.exists || {};
for (var id in alias) {
uriList[id] = baseUrl + alias[id];
}
for (var id in asyncDeps) {
var depsArr = [],
data = asyncDeps[id];
for (var i in data) {
if (!cssExists[data[i]]) {
depsArr.push(uriList[data[i]]);
}
}
asyncDeps[id] = depsArr;
}
atmLoader.asyncDeps = asyncDeps;
atmLoader.cssExists = cssExists;
};
function addCss(uriArr) {
for (var i in uriArr) {
var uri = uriArr[i];
if(uri.indexOf(baseUrl) === -1){
uri = baseUrl + uri;
}
if(!atmLoader.cssExists[uri] && uri){
createStylesheet(uri);
}
}
}
if (config) {
config = (new Function('return ' + config))();
setConfig(config);
}
function addNeeds(ids) {
var id;
for (var i in ids) {
id = ids[i];
needs[id] = 1;
}
}
// 所依赖的js的加载状态
function getStatus(deps) {
var status = true;
for (var id in deps){
if (!list[id] || list[id].status < 40){
return false;
}
}
return status;
}
// 定义require
function require(id) {
return modules[id].exports;
}
// 如果ids是字符串,则转换为数组返回
function getIds(ids) {
return typeof ids==='string'? [ids]: ids;
}
// 获取id对应的url路径
function getUri(id) {
return uriList[id];
}
// 创建js节点
var createdJs = {};
function createScript(url) {
if (createdJs[url]) {
return;
}
createdJs[url] = true;
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
var firstScript = document.getElementsByTagName('script')[0];
firstScript.parentNode.insertBefore(script, firstScript);
return script;
}
// 创建css节点
var createdCss = {}
function createStylesheet(href) {
if (createdCss[href]) {
return;
}
createdCss[href] = true;
var head = document.getElementsByTagName('head')[0];
var link = document.createElement('link');
link.href = href;
link.rel = 'stylesheet';
link.type = 'text/css';
head.appendChild(link);
}
// 把 数组转换为对象
// eg: ['a','b'] To {a: 1, b: 1}
function arrToObj(arr) {
var obj = {};
for (var i in arr) {
var id = arr[i];
obj[id] = 1;
}
return obj;
}
})(window);