动态加载的JavaScript库什么时候可用?

时间:2013-11-04 01:00:33

标签: javascript javascript-framework

我编写了JavaScript库以使用FileSaver.js及其相关库。但是,每当有人想要使用我的库时,我都不想总是加载FileSaver.js。而且我不想强迫他们自己加载所有与script标签相关的各种与FileSaver相关的JavaScript库(甚至加载我的一个也可以这样做)。

相反,我更喜欢的是这样的。当他们调用我的createImage函数时,它首先执行以下操作:

function createImage(image, name) {
  if (typeof(saveAs) !== 'function') {
    var element = document.createElement('script');
    element.async = false;
    element.src = 'FileSaver.js';
    element.type = 'text/javascript';
    (document.getElementsByTagName('head')[0]||document.body).appendChild(element);
  }
  // now do the saveImage code
}

问题是,在上述之后,仍然没有定义saveAs函数。只有 后我的createImage完成才是最终定义的saveAs函数。

5 个答案:

答案 0 :(得分:9)

整体解决方案是使用模块系统。 AMD(在我的观察 - 请 - 请 - 不要 - 开始 - 圣战 - 意见)可能是最常用的浏览器异步代码加载系统。 AMD只是一个规范,但像require.js这样的东西是一个非常流行的使用AMD模块的工具。

您可以定义模块之间的依赖关系,而require.js将在需要时获取它们。一般的想法是模仿其他语言(如java,C#或python)的导入/命名空间功能。 “代码共享”我认为这个词是什么?

只需将所有代码放在一个回调函数中,该函数在加载依赖项后运行,这样就可以确保所需的对象和方法存在。

更新2015

只是一个附录。虽然上面的信息仍然正确,但前端代码管理正在迅速向Webpack和Browserify等解决方案发展,它们捆绑和连接任何模块类型的代码,并且都具有动态代码加载功能(webpack调用此代码拆分)。加上依赖管理的npm指数增长,开始使AMD的相关性降低。

答案 1 :(得分:1)

好的,你需要做的就是听脚本完成加载。不幸的是,这个代码存在一些错误,即< 7。

这是Mootools Asset.javascript加载脚本并在完成时调用回调的方式:

var loadScript = function (source, properties) {
    properties || (properties = {});
    var script = document.createElement('script');
    script.async = true;
    script.src = source;
    script.type = 'text/javascript';
    var doc = properties.document || document, load = properties.onload || properties.onLoad;
    return delete properties.onload, delete properties.onLoad, delete properties.document, 
    load && (script.addEventListener ? script.addEventListener("load", load) : script.attachEvent("readystatechange", function() {
        [ "loaded", "complete" ].indexOf(this.readyState) >= 0 && load.call(this);
    })), script.set(properties).appendChild(doc.head);
}

现在在loadImage中,您可以按如下方式加载文件库:

function createImage(image, name) {
  function createImg() {
      // now do the saveImage code
  }
  if (typeof(saveAs) !== 'function') {
     loadScript("FileSaver.js", {onLoad: createImg});//load library
  }
  else {
     createImg();
  }
}

适用于大多数浏览器。

答案 2 :(得分:0)

使用Head.js:http://headjs.com/

它将按需加载脚本。

答案 3 :(得分:0)

所以我同意AMD的评论(不能将代码阻止到评论中......)

这是我为FileSaver.js做的事情

首先在我的requirejs config / main.js中:

(function() {
    // REMEMBER TO DUPLICATE CHANGES IN GRUNTFILE.JS
    requirejs.config({
        paths: {
            "jquery": "PATH/jquery.min", // NO .js
            "lib.filesaver" : "PATH/FileSaver", // NO .js
            "shim.blob" : "PATH/Blob" // NO .js
        },
        shim: {
            "lib.filesaver": {deps: ["shim.blob"]}
        }
    });

    define([
        "jquery"
    ], function(
        $
        ) {
            $(document).ready(function() {
                // start up code...
            });
        return {};
        });
})();

然后我将Blob.js / jquery和Filersaver放在正确的位置

我还为IE10之前创建了一个IEShim

define([], function () {
    /**
     * @class IEshims
     * container for static IE shim functions
     */
    var IEShims = {
        /**
         * saveFile, pops up a built in javascript file as a download
         * @param {String} filename, eg doc.csv
         * @param {String} filecontent eg "this","is","csv"
         */
        saveAs: function (filename, filecontent, mimetype ) {
            var w = window.open();
            var doc = w.document;
            doc.open( mimetype,'replace');
            doc.charset = "utf-8";
            doc.write(filecontent);
            doc.close();
            doc.execCommand("SaveAs", null, filename);
        }
    };
    return IEShims;
});

最后,当我想使用Filesaver时,需要它(对于糟糕的浏览器,还有IEShim)

define([
"lib.filesaver",
"IEShims"
],
function (
    FileSaver, // it's empty, see saveAs global var
    IEShims
    ) {
...
    var fileName = "helloworld.txt";
    var fileContents = "Me haz file contents, K Thx Bye";
    var mimeType = "text/plain";
    if(saveAs) {
        var blob = new Blob(
            [fileContents],
            {type: mimeType + ";charset=" + document.characterSet}
        );
        saveAs(blob, fileName);
    } else {
        IEShims.saveAs(fileName, fileContents,mimeType );
    }
    ...
};

答案 4 :(得分:0)

最简单的答案是将您的代码放在您创建的onload标记的script处理程序中:

<script>
  var firstScript = document.getElementsByTagName('script')[0],
      js = document.createElement('script');
  js.src = 'https://cdnjs.cloudflare.com/ajax/libs/Snowstorm/20131208/snowstorm-min.js';
  js.onload = function () {
    // do stuff with your dynamically loaded script
    snowStorm.snowColor = '#99ccff';
  };
  firstScript.parentNode.insertBefore(js, firstScript);
</script>

以这种方式动态加载脚本done by Facebook