北京前端同事有个项目里用了ace-admin这个管理平台框架,不太喜欢这个框架,不过在里面发现了一段异步加载js脚本文件的代码,修改了一下贴到这里,以后自己项目里也可以用:
export function ready (optionalScriptsDependencies, cb) { if (arguments.length === 1) { waitForReady(cb); } else if (arguments.length === 2) { loadScripts(optionalScriptsDependencies, () => { waitForReady(cb); }); } } function waitForReady (cb) { $(document).ready(function () { cb && cb(); }); } // ajaxLoadedScripts要放到loadScripts外才能起到全局统计的作用 const ajaxLoadedScripts = {}; function loadScripts (scripts, callback) { $.ajaxPrefilter('script', (opts) => { opts.cache = true; }); setTimeout(() => { function finishLoading () { typeof callback === 'function' && callback(); } let deferredCount = 0; let resolved = 0; for (let i = 0; i < scripts.length; i++) { if (scripts[i]) { (() => { const scriptName = 'js-' + scripts[i].replace(/[^\w\d-]/g, '-').replace(/--/g, '-'); ajaxLoadedScripts[scriptName] !== true && deferredCount++; })(); } } function nextScript (index) { index += 1; if (index < scripts.length) { loadScript(index); } else { finishLoading(); } } function loadScript (index) { index = index || 0; if (!scripts[index]) { return nextScript(index); } const scriptName = 'js-' + scripts[index].replace(/[^\w\d-]/g, '-').replace(/--/g, '-'); // 只加载目前为止没有加载过的脚本 if (ajaxLoadedScripts[scriptName] !== true) { $.getScript(scripts[index]).done(() => { ajaxLoadedScripts[scriptName] = true; }).complete(() => { ++resolved >= deferredCount ? finishLoading() : nextScript(index); }); } else { nextScript(index); } } deferredCount > 0 ? loadScript() : finishLoading(); }, 10); }
使用方法很简单,碰到有js文件依赖的时候,这样使用ready方法:
ready([ '../assets/js/jquery.validate.js', ], () => { // 这时依赖的js脚本文件已经加载完毕了,document ready后要执行的代码放在此处 });
如果没有js文件依赖的话,这样使用ready方法:
ready(() => { // document ready后要执行的代码放在此处 });
下面是根据以前自己写过的方法封装一下得到的代码,作用差不多(没像上面的例子那样判断脚本是否已加载过,不过用document.write生成script标签加载js文件的话,浏览器自己也会做缓存处理的,问题不大吧-_-):
function loadAsyncScripts(scripts, callback) { const scriptsLength = scripts.length; scripts.forEach(item => loadAsyncScript(item, checkWhetherToExecuteCallback.bind(null, scriptsLength, callback))); } let counter = 0; function checkWhetherToExecuteCallback (scriptsLength, cb) { ++counter === scriptsLength && cb(); } function loadAsyncScript(src, callback) { var head = document.getElementsByTagName('head')[0]; var script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.setAttribute('src', src); script.setAttribute('async', true); script.setAttribute('defer', true); head.appendChild(script); if (document.all) { script.onreadystatechange = function () { var state = this.readyState; if (state === 'loaded' || state === 'complete') { callback(); } } } else { script.onload = function () { callback(); } } }