LoadJS与myload实现

本文介绍了如何使用LoadJS和自编的myload来异步加载静态资源,以满足产品定制化开发的需求。通过这种方式,用户可以重写前端验证的js或自定义css样式。文章提到了LoadJS的常见用法,并提供了myload的使用示例,同时附带了LoadJS的源码参考链接。

LoadJS与myload实现


注意本次文章有点水
源码:链接: https://pan.baidu.com/s/1KgG1wvBqhOe4nJO70pgUVA
提取码:r31h


异步加载静态资源:
原本我的想法是使用定时器,或者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 导出
})();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值