文章目录

  • 背景
  • 解决方案
  • 1 目前暂可行的实施方案
  • 2 回调函数
  • 3 异步加载
  • 结束语
  • 参考文章


背景

为了方便用户使用sdk,从用户角度想简化引入各种css、js库的麻烦琐事。
问题来了,用document.write可以完美解决这个问题,但问题的问题是虽然浏览器有警告,但它还是执行了,就不知道哪一天会不会直接error出现或者拦截了。
最好的方式当然是采用es6使用import模块的方式,这里是考虑了老的加载方式,即直接通过引入script标签引入js库。
现实情况是难免会有用到引入第三方库的情况。
这里也不考虑使用requirejs的方式,因为用了这个还不如直接用es6自带的import来的快。

Why you should avoid using document.write, specifically for scripts injection

var sNew = document.createElement("script");
sNew.async = true;
sNew.src = "https://example.com/script.min.js";
var s0 = document.getElementsByTagName('script')[0];
s0.parentNode.insertBefore(sNew, s0);

解决方案

1 目前暂可行的实施方案

// 动态加载js脚本文件
function loadScript(url) {
  document.write(`\x3Cscript type="text/javascript" src="${url}">\x3C/script>`);
}

// 动态加载css文件
function loadStyles(url) {
  document.write(
    `\x3Clink type="text/css" rel="stylesheet" href="${url}">\x3C/link>`
  );
}
(function () {
  loadStyles(ipconfig + "/css/a.css");
  loadStyles(ipconfig + "/css/b.css");
  loadScript(ipconfig + "/lib/a.js");
  loadScript(ipconfig + "/lib/b.js");})();

2 回调函数

意味着要使用使用第三方的对象需要在回调函数中使用

function loadScript(url, callback){
  var script = document.createElement ("script")
  script.type = "text/javascript";
  if (script.readyState){ //IE
      script.onreadystatechange = function(){
          if (script.readyState == "loaded" || script.readyState == "complete"){
              script.onreadystatechange = null;
              callback();
          }
      };
  } else { //Others
      script.onload = function(){
          callback();
      };
  }
  script.src = url;
  document.getElementsByTagName("head")[0].appendChild(script);
}

loadScript(urlCesium, function(){alert('加载成功')});

3 异步加载

写法1 ol中的使用方法

class LazyLoader {
  /**
   * @param {string} url
   * @api
   */
  constructor(url) {
    /**
     * @type {Promise<undefined>}
     * @protected
     */
    this.promise;

    /**
     * @private
     * @type {string}
     */
    this.url_ = url;
  }

  /**
   * @return {Promise<undefined>}
   * @api
   */
  load() {
    if (!this.promise) {
      // not yet loading
      this.promise = new Promise((resolve, reject) => {
        const script = document.createElement("script");
        script.onload = () => resolve();
        script.onerror = () => reject();
        document.head.appendChild(script);
        script.src = this.url_;
      });
    }
    return this.promise;
  }
}
const url = "http://localhost:9300/a.js";
const aLazyLoader = new LazyLoader(url);
var a  = cesiumLazyLoader.load().then(() => console.log('使用a模块中的对象'));

写法2 Cesium中的使用方法

/**
 * @private
 */
function loadAndExecuteScript(url) {
  var deferred = when.defer();
  var script = document.createElement("script");
  script.async = true;
  script.src = url;

  var head = document.getElementsByTagName("head")[0];
  script.onload = function () {
    script.onload = undefined;
    head.removeChild(script);
    deferred.resolve();
  };
  script.onerror = function (e) {
    deferred.reject(e);
  };

  head.appendChild(script);

  return deferred.promise;
}
export default loadAndExecuteScript;

// 使用方法
var url = buildModuleUrl("ThirdParty/google-earth-dbroot-parser.js");
var oldValue = window.cesiumGoogleEarthDbRootParser;
var dbrootParserPromise = loadAndExecuteScript(url).then(function () {
  dbrootParser = window.cesiumGoogleEarthDbRootParser(protobufMinimal);
  if (defined(oldValue)) {
    window.cesiumGoogleEarthDbRootParser = oldValue;
  } else {
    delete window.cesiumGoogleEarthDbRootParser;
  }
});

结束语

其实使用es6的模块化+异步的方法能更好的解决这个问题。如果有其他办法后续再说吧

参考文章

https://stackoverflow.com/questions/7761149/dynamically-added-script-will-not-execute

I am dynamically adding a script of a github gist. If I added it to the html before the page loads, the script will execute. But If I try to add it to the page after it loads it adds the script to the page but doesn’t execute it.

在 DOM 中动态执行脚本

js动态加载第三方js库(带onload功能)

动态插入的script脚本执行时间

editorJs2.async = false

动态加载js不执行解决办法(测试不成功)

原生js 怎么引入axios 原生js 怎么引入第三方包_动态加载

这个问题的产生原因是:我们项目有一个主index文件,在主index文件中需要根据参数来判断是加载pc.html的内容还是加载mobile.html的内容,一开始是使用jquery来做的,没有问题,后来想着jquery也有80多k就想着优化下,结果将所有有$的地方都转为原生的js代码,js,css,dom也都加载正常,就是页面显示不出来,动态加载的js没有执行,查了很长时间才找到方案,如上图;