异步加载静态资源:
原本我的想法是使用定时器,或者es6语法中的async、generator或者promise对象实现。但是查看到有现成的js插件即可完成,因此就查看了相关代码进行实现。
常见用法:产品定制化开发需求需要,用户可能重写js中前端验证,或者css样式等
myload:自己编码实现
//加载js
function myloadjs(url,callback){
var script=document.createElement('script');
script.type="text/javascript";
script.src=url;
script.attr={"async":""};
addcallback(callback, script, null);
}
//加载css
function myloadcss(url , callback) {
var link = document.createElement('link');
link.rel = 'stylesheet';
var pathStripped = url.replace(/^(css|img)!/, '')
link.href = pathStripped;
var isLegacyIECss = 'hideFocus' in link; // tag IE9+
if (isLegacyIECss && link.relList) {
isLegacyIECss = 0;
link.rel = 'preload';
link.as = 'style';
}
addcallback(callback, link, null);
}
//加载img
function myloadimg(url, id, callback) {
var img = document.createElement('img');
var pathStripped = url.replace(/^(css|img)!/, '')
if (/(^img!|\.(png|gif|jpg|svg)$)/.test(url)) {
img.src = pathStripped;
img.style="width:100px";
}
addcallback(callback, img, id);
}
//添加回调函数的函数
function addcallback(callback, tagter, id) {
/*--------核心之一-----------*/
tagter.onload = tagter.onerror = tagter.onbeforeload = function(){
callback();
}
/**-----------------------------**/
if(id) {
document.getElementById(id).appendChild(tagter);
} else {
document.getElementsByTagName('head')[0].appendChild(tagter);
}
}
//日志信息
function println(msg) {
console.log("myload日志系统======>"+msg)
}
使用:
文件目录
<!DOCTYPE HTML lang="zh-CN">
<html>
<head>
<meta charset="utf-8"/>
<title>测试loadjs/myload</title>
<script type="text/javascript" src="../js/myload.js"></script>
<script type="text/javascript" src="../js/loadjs.js"></script>
</head>
<body>
<div style="text-align:center;">测试loadjs/myload</div>
<div id="test">sdf</div>
<div id="img"></div>
</body>
<script type="text/javascript">
myloadjs("../js/cctest.js",function(){
println("myloadjs加载js完毕");
});
myloadcss("../css/index.css", function(){
println("myloadcss加载完毕css");
})
myloadimg("../img/index.png", "img", function(){
println("myloadimg加载完毕img");
})
</script>
<script type="text/javascript">
loadjs("../js/cctest.js","test", function(){
fntest("loadjs 加载的js方法");
});
// loadjs.reset();
loadjs("../js/cctest.js","test1", function(){
fntest("loadjs 加载的js方法2");
});
</script>
</html> type="text/javascript" src="../js/loadjs.js"></script>
</head>
<body>
<div style="text-align:center;">测试loadjs/myload</div>
<div id="test">sdf</div>
<div id="img"></div>
</body>
<script type="text/javascript">
myloadjs("../js/cctest.js",function(){
println("myloadjs加载js完毕");
});
myloadcss("../css/index.css", function(){
println("myloadcss加载完毕css");
})
myloadimg("../img/index.png", "img", function(){
println("myloadimg加载完毕img");
})
</script>
<script type="text/javascript">
loadjs("../js/cctest.js","test", function(){
fntest("loadjs 加载的js方法");
});
// loadjs.reset();
loadjs("../js/cctest.js","test1", function(){
fntest("loadjs 加载的js方法2");
});
</script>
</html>
结果:

LoadJS:源码参考https://github.com/muicss/loadjs
loadjs = (function () {
/** Global dependencies.全局依赖项
* @global {Object} document - DOM */
var devnull = function() {}, bundleIdCache = {},bundleResultCache = {},bundleCallbackQueue = {};
/** Subscribe to bundle load event. 订阅捆绑加载事件
* @param {string[]} bundleIds - Bundle ids 绑定id
* @param {Function} callbackFn - The callback function 绑定回调事件 */
function subscribe(bundleIds, callbackFn) {
bundleIds = bundleIds.push ? bundleIds : [bundleIds];// listify 精化
var depsNotFound = [],i = bundleIds.length,numWaiting = i, fn,bundleId, r, q;
fn = function (bundleId, pathsNotFound) { // define callback function 定义回调函数
if (pathsNotFound.length) depsNotFound.push(bundleId);
numWaiting--;
if (!numWaiting) callbackFn(depsNotFound);
};
while (i--) {// register callback 注册回调函数
bundleId = bundleIds[i];
// execute callback if in result cache 如果在结果缓存中,则执行回调
r = bundleResultCache[bundleId];
if (r) { fn(bundleId, r); continue; }
// add to callback queue 添加到回调队列
q = bundleCallbackQueue[bundleId] = bundleCallbackQueue[bundleId] || [];
q.push(fn);
}
}
/** Publish bundle load event. 发布捆绑加载事件
* @param {string} bundleId - Bundle id 绑定id
* @param {string[]} pathsNotFound - List of files not found 找不到文件列表 */
function publish(bundleId, pathsNotFound) {
// exit if id isn't defined 如果未定义ID,则退出
if (!bundleId) return;
var q = bundleCallbackQueue[bundleId];
bundleResultCache[bundleId] = pathsNotFound; // cache result 缓存结果
if (!q) return; // exit if queue is empty 如果队列为空,则退出
while (q.length) {// empty callback queue 空回调队列
q[0](bundleId, pathsNotFound);
q.splice(0, 1);
}
}
/** Execute callbacks. 执行回调
* @param {Object or Function} args - The callback args 回调参数
* @param {string[]} depsNotFound - List of dependencies not found 未找到依赖项列表 */
function executeCallbacks(args, depsNotFound) {
// accept function as argument 接受函数作为参数
if (args.call) args = {success: args};
// success and error callbacks 成功和错误回调
if (depsNotFound.length) (args.error || devnull)(depsNotFound);
else (args.success || devnull)(args);
}
/** Load individual file. 加载单个文件
* @param {string} path - The file path 文件路径
* @param {Function} callbackFn - The callback function 回调函数 */
function loadFile(path, callbackFn, args, numTries) {
var doc = document,async = args.async, maxTries = (args.numRetries || 0) + 1, beforeCallbackFn = args.before || devnull,
pathStripped = path.replace(/^(css|img)!/, ''), isLegacyIECss, e;
numTries = numTries || 0;
if (/(^css!|\.css$)/.test(path)) {// css css文件
e = doc.createElement('link');
e.rel = 'stylesheet';
e.href = pathStripped;
isLegacyIECss = 'hideFocus' in e; // tag IE9+
// use preload in IE Edge (to detect load errors) 在IE边缘使用预加载(检测加载错误)
if (isLegacyIECss && e.relList) {
isLegacyIECss = 0;
e.rel = 'preload';
e.as = 'style';
}
} else if (/(^img!|\.(png|gif|jpg|svg)$)/.test(path)) {// image 图片
e = doc.createElement('img');
e.src = pathStripped;
} else { // javascript javascript 文件
e = doc.createElement('script');
e.src = path;
e.async = async === undefined ? true : async;
}
e.onload = e.onerror = e.onbeforeload = function (ev) {
var result = ev.type[0];
// treat empty stylesheets as failures to get around lack of onerror
if (isLegacyIECss) { // support in IE9-11
try {
if (!e.sheet.cssText.length) result = 'e';
} catch (x) {
// sheets objects created from load errors don't allow access to
// `cssText` (unless error is Code:18 SecurityError)
if (x.code != 18) result = 'e';
}
}
// handle retries in case of load failure 加载失败时处理重试
if (result == 'e') {
numTries += 1;// increment counter 增量计数器
if (numTries < maxTries) {// exit function and try again 退出函数并重试
return loadFile(path, callbackFn, args, numTries);
}
} else if (e.rel == 'preload' && e.as == 'style') {
// activate preloaded stylesheets 激活预加载的样式表
return e.rel = 'stylesheet'; // jshint ignore:line
}
callbackFn(path, result, ev.defaultPrevented); // execute callback 执行回调
};
// add to document (unless callback returns `false`)
if (beforeCallbackFn(path, e) !== false) doc.head.appendChild(e);
}
/** Load multiple files. 加载多个文件
* @param {string[]} paths - The file paths 文件路径
* @param {Function} callbackFn - The callback function 回调方法 */
function loadFiles(paths, callbackFn, args) {
paths = paths.push ? paths : [paths];// listify paths 修整路径
var numWaiting = paths.length, x = numWaiting, pathsNotFound = [], fn, i;
fn = function(path, result, defaultPrevented) { // define callback function 定义回调函数
// handle error 句柄错误
if (result == 'e') pathsNotFound.push(path);
// handle beforeload event. If defaultPrevented then that means the load
// will be blocked (ex. Ghostery/ABP on Safari)
//处理beforeload事件。如果默认值被阻止,则意味着负载将被阻止(例如,在Safari上的ghostery/abp)
if (result == 'b') {
if (defaultPrevented) pathsNotFound.push(path);
else return;
}
numWaiting--;
if (!numWaiting) callbackFn(pathsNotFound);
};
// load scripts 加载script
for (i=0; i < x; i++) loadFile(paths[i], fn, args);
}
/** Initiate script load and register bundle. 启动脚本加载和注册捆绑包 */
function loadjs(paths, arg1, arg2) {
var bundleId, args;
if (arg1 && arg1.trim) bundleId = arg1; // bundleId (if string)
args = (bundleId ? arg2 : arg1) || {};// args (default is {})
if (bundleId) {// throw error if bundle is already defined
if (bundleId in bundleIdCache) {
throw "LoadJS";
} else { bundleIdCache[bundleId] = true; }
}
function loadFn(resolve, reject) {
loadFiles(paths, function (pathsNotFound) {
executeCallbacks(args, pathsNotFound); // execute callbacks 执行回调
if (resolve) {// resolve Promise 解决承诺
executeCallbacks({success: resolve, error: reject}, pathsNotFound);
}
publish(bundleId, pathsNotFound); // publish bundle load event 发布捆绑加载事件
}, args);
}
if (args.returnPromise) return new Promise(loadFn);
else loadFn();
}
/** Execute callbacks when dependencies have been satisfied. 满足依赖项后执行回调 */
loadjs.ready = function ready(deps, args) {
subscribe(deps, function (depsNotFound) {// subscribe to bundle load event 订阅捆绑加载事件
executeCallbacks(args, depsNotFound); // execute callbacks 执行回调
});
return loadjs;
};
/** Manually satisfy bundle dependencies. 手动满足捆绑依赖项 */
loadjs.done = function done(bundleId) {
publish(bundleId, []);
};
/** Reset loadjs dependencies statuses 重置LoadJS依赖项状态 */
loadjs.reset = function reset() {
bundleIdCache = {}; bundleResultCache = {}; bundleCallbackQueue = {};
};
/** Determine if bundle has already been defined 确定是否已定义绑定 */
loadjs.isDefined = function isDefined(bundleId) {
return bundleId in bundleIdCache;
};
return loadjs;// export 导出
})();
本文介绍了如何使用LoadJS和自编的myload来异步加载静态资源,以满足产品定制化开发的需求。通过这种方式,用户可以重写前端验证的js或自定义css样式。文章提到了LoadJS的常见用法,并提供了myload的使用示例,同时附带了LoadJS的源码参考链接。

3172

被折叠的 条评论
为什么被折叠?



