动态加载JavaScript文件


167

如何可靠,动态地加载JavaScript文件?这将用于实现模块或组件,该模块或组件在“初始化”时将根据需要动态加载所有需要的JavaScript库脚本。

使用该组件的客户端不需要加载<script>实现该组件的所有库脚本文件(并将标记手动插入其网页),只需加载“主”组件脚本文件即可。

主流JavaScript库如何做到这一点(原型,jQuery等)? 这些工具是否将多个JavaScript文件合并到脚本文件的单个可再发行“构建”版本中?还是对附属的“库”脚本进行动态加载?

这个问题的补充:加载动态包含的JavaScript文件后,是否可以处理事件? 原型具有document.observe文档范围的事件。例:

document.observe("dom:loaded", function() {
  // initially hide all containers for tab content
  $$('div.tabcontent').invoke('hide');
});

脚本元素有哪些可用事件?


Answers:


84

您可以编写动态脚本标签(使用Prototype):

new Element("script", {src: "myBigCodeLibrary.js", type: "text/javascript"});

这里的问题是我们不知道外部脚本文件何时完全加载。

我们经常希望我们的依赖代码在下一行,并且喜欢编写如下代码:

if (iNeedSomeMore) {
    Script.load("myBigCodeLibrary.js"); // includes code for myFancyMethod();
    myFancyMethod(); // cool, no need for callbacks!
}

有一种聪明的方法可以注入脚本依赖项,而无需回调。您只需要通过同步AJAX请求提取脚本并在全局级别评估脚本。

如果您使用原型,则Script.load方法如下所示:

var Script = {
    _loadedScripts: [],
    include: function(script) {
        // include script only once
        if (this._loadedScripts.include(script)) {
            return false;
        }
        // request file synchronous
        var code = new Ajax.Request(script, {
            asynchronous: false,
            method: "GET",
            evalJS: false,
            evalJSON: false
        }).transport.responseText;
        // eval code on global level
        if (Prototype.Browser.IE) {
            window.execScript(code);
        } else if (Prototype.Browser.WebKit) {
            $$("head").first().insert(Object.extend(
                new Element("script", {
                    type: "text/javascript"
                }), {
                    text: code
                }
            ));
        } else {
            window.eval(code);
        }
        // remember included script
        this._loadedScripts.push(script);
    }
};

我该怎么做才能使其在跨域环境中正常工作?(从加载脚本http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js
2014年


@Ciastopiekarz:我不控制web.archive.org
user2284570

然后,您必须使用其他程序来抓取要访问的数据,并将其提供给自己
David Schumann

什么是Ajax.Request?
bluejayke

72

javascript中没有import / include / require,但是有两种主要方法可以实现所需的功能:

1-您可以通过AJAX调用加载它,然后使用eval。

这是最直接的方法,但是由于Javascript安全设置,它仅限于您的域,并且使用eval为漏洞和黑客打开了大门。

2-在HTML中添加带有脚本URL的脚本标签。

绝对是最好的方法。您甚至可以从外部服务器加载脚本,并且使用浏览器解析器评估代码是干净的。您可以将标签放置在网页的顶部或正文的底部。

此处讨论和说明了这两种解决方案。

现在,您必须了解一个大问题。这样做意味着您需要远程加载代码。现代的Web浏览器将加载文件并继续执行您当前的脚本,因为它们会异步加载所有内容以提高性能。

这意味着,如果您直接使用这些技巧,则在您要求加载新代码后,将无法在下一行使用它,因为它将继续加载。

EG:my_lovely_script.js包含MySuperObject

var js = document.createElement("script");

js.type = "text/javascript";
js.src = jsFilePath;

document.body.appendChild(js);

var s = new MySuperObject();

Error : MySuperObject is undefined

然后,您按F5重新加载页面。而且有效!令人困惑...

那么该怎么办呢?

好吧,您可以使用作者在我给您提供的链接中建议的技巧。总而言之,对于有急事的人,他在加载脚本时使用en事件运行回调函数。因此,您可以将所有使用远程库的代码放入回调函数中。EG:

function loadScript(url, callback)
{
    // adding the script tag to the head as suggested before
   var head = document.getElementsByTagName('head')[0];
   var script = document.createElement('script');
   script.type = 'text/javascript';
   script.src = url;

   // then bind the event to the callback function 
   // there are several events for cross browser compatibility
   script.onreadystatechange = callback;
   script.onload = callback;

   // fire the loading
   head.appendChild(script);
}

然后,在脚本被加载到lambda函数中之后,编写要使用的代码:

var myPrettyCode = function() {
    // here, do what ever you want
};

然后,您运行所有这些:

loadScript("my_lovely_script.js", myPrettyCode);

好,我知道了。但是写所有这些东西很痛苦。

好吧,在这种情况下,您可以一如既往地使用出色的免费jQuery框架,该框架可让您在一行中完成相同的操作:

$.getScript("my_lovely_script.js", function() {
    alert("Script loaded and executed.");
    // here you can use anything you defined in the loaded script
});

11
不敢相信这个答案是多么被低估了。谢谢。
naftalimich

2
我敢打赌,这是因为人们不喜欢阅读第一行,除非它向他们保证,如果他们“只要遵循这三个成功的秘密步骤,他们就会变得富有”。
2013年

这可行。我希望在这里分享我的经验可以节省您的时间,因为我花了很多时间在此上。我正在使用Angular 6和应用的模板(html,css,jquery)问题是模板有一个js文件,该文件在加载html元素以附加侦听器事件后加载。Angular应用加载后,该js文件很难执行。将其添加到angular app(angular.json)脚本标签会捆绑它们,但加载后不执行该js文件。太多的代码无法用打字稿重写,因此这是非常有用的。接下来的评论我就把这例子becuse评论长度
诺尔Lababidi

我只是按如下方式使用此代码:ngAfterViewInit(){debugger; $ .getScript(“ / assets / js / jquery.app.js”,function(){alert(“脚本已加载并执行。”); //在这里您可以使用在已加载脚本中定义的任何内容}); }
Nour Lababidi

对于我的角度对“$”跟着这个:stackoverflow.com/questions/32050645/...
诺尔Lababidi

28

最近jQuery中使用了一个简单得多的版本

<script src="scripts/jquery.js"></script>
<script>
  var js = ["scripts/jquery.dimensions.js", "scripts/shadedborder.js", "scripts/jqmodal.js", "scripts/main.js"];
  var $head = $("head");
  for (var i = 0; i < js.length; i++) {
    $head.append("<script src=\"" + js[i] + "\"></scr" + "ipt>");
  }
</script>

在我在IE6 / 7,Firefox,Safari,Opera中测试过的每种浏览器中,它的效果都很好。

更新:无 jQuery版本:

<script>
  var js = ["scripts/jquery.dimensions.js", "scripts/shadedborder.js", "scripts/jqmodal.js", "scripts/main.js"];
  for (var i = 0, l = js.length; i < l; i++) {
    document.getElementsByTagName("head")[0].innerHTML += ("<script src=\"" + js[i] + "\"></scr" + "ipt>");
  }
</script>

25
太好了……除非您尝试加载jquery。

1
看起来jQuery会在将来的版本中将Require插件引入jQuery Core:plugins.jquery.com/project/require
Adam

1
使用jQuery的一种更好的方法是使用$.getScript。看我的答案。
Muhd 2012年

1
Modernizr(yepnope.js)或lab.js是适用的解决方案。对于移动或许多其他情况,使用繁重的脚本库(必须首先加载)不是最合适的答案。
1nfiniti '02

2
@MaulikGangani较旧的浏览器和html验证程序会将其解释为结束脚本的令牌。
travis

20

我所做的基本上与您使用Adam时所做的相同,但是稍作修改以确保我将附加到head标签上来完成工作。我只是创建了一个包含函数(下面的代码)来处理脚本和CSS文件。

此函数还检查以确保脚本或CSS文件尚未动态加载。它不检查手工编码的值,并且可能有更好的方法来做到这一点,但它确实达到了目的。

function include( url, type ){
    // First make sure it hasn't been loaded by something else.
    if( Array.contains( includedFile, url ) )
        return;

    // Determine the MIME-type
    var jsExpr = new RegExp( "js$", "i" );
    var cssExpr = new RegExp( "css$", "i" );
    if( type == null )
        if( jsExpr.test( url ) )
            type = 'text/javascript';
        else if( cssExpr.test( url ) )
            type = 'text/css';

    // Create the appropriate element.
    var tag = null;
    switch( type ){
        case 'text/javascript' :
            tag = document.createElement( 'script' );
            tag.type = type;
            tag.src = url;
            break;
        case 'text/css' :
            tag = document.createElement( 'link' );
            tag.rel = 'stylesheet';
            tag.type = type;
            tag.href = url;
            break;
    }

    // Insert it to the <head> and the array to ensure it is not
    // loaded again.
    document.getElementsByTagName("head")[0].appendChild( tag );
    Array.add( includedFile, url );
}

没有比Pickle更多的上下文,恐怕我没有任何建议。上面的代码按原样工作,它是直接从正常运行的项目中提取的。
Palhorse 2010年

5
@ palehorse,Mike和Muhd是正确的,它可能在您的项目中有效,但是那是因为必须在项目的其他位置定义“ includedFile”和“ Array”变量,所以该代码本身无法运行,可能是最好对其进行编辑,以便它可以在项目的上下文之外运行,或者至少添加注释以说明那些未定义的变量是什么(类型等)
user280109 2014年

14

另一个很棒的答案

$.getScript("my_lovely_script.js", function(){


   alert("Script loaded and executed.");
  // here you can use anything you defined in the loaded script

 });

https://stackoverflow.com/a/950146/671046


2
我该怎么做才能使其在跨域环境中正常工作?(正在加载脚本http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js
user2284570

9

这是我发现的一些示例代码...有人有更好的方法吗?

  function include(url)
  {
    var s = document.createElement("script");
    s.setAttribute("type", "text/javascript");
    s.setAttribute("src", url);
    var nodes = document.getElementsByTagName("*");
    var node = nodes[nodes.length -1].parentNode;
    node.appendChild(s);
  }

我该怎么做才能使其在跨域环境中正常工作?(正在加载脚本http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js
user2284570

6

如果已经加载了jQuery,则应使用$ .getScript

与此处的其他答案相比,这具有一个优点,因为您具有内置的回调函数(以确保在依赖代码运行之前加载脚本),并且可以控制缓存。


4

如果要加载SYNC脚本,则需要将脚本文本直接添加到HTML HEAD标签。将其添加为将触发ASYNC加载。要从外部文件同步加载脚本文本,请使用XHR。下面是一个快速示例(在本帖子和其他帖子中使用了其他答案的一部分):

/*sample requires an additional method for array prototype:*/

if (Array.prototype.contains === undefined) {
Array.prototype.contains = function (obj) {
    var i = this.length;
    while (i--) { if (this[i] === obj) return true; }
    return false;
};
};

/*define object that will wrap our logic*/
var ScriptLoader = {
LoadedFiles: [],

LoadFile: function (url) {
    var self = this;
    if (this.LoadedFiles.contains(url)) return;

    var xhr = new XMLHttpRequest();
    xhr.onload = function () {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
                self.LoadedFiles.push(url);
                self.AddScript(xhr.responseText);
            } else {
                if (console) console.error(xhr.statusText);
            }
        }
    };
    xhr.open("GET", url, false);/*last parameter defines if call is async or not*/
    xhr.send(null);
},

AddScript: function (code) {
    var oNew = document.createElement("script");
    oNew.type = "text/javascript";
    oNew.textContent = code;
    document.getElementsByTagName("head")[0].appendChild(oNew);
}
};

/*Load script file. ScriptLoader will check if you try to load a file that has already been loaded (this check might be better, but I'm lazy).*/

ScriptLoader.LoadFile("Scripts/jquery-2.0.1.min.js");
ScriptLoader.LoadFile("Scripts/jquery-2.0.1.min.js");
/*this will be executed right after upper lines. It requires jquery to execute. It requires a HTML input with id "tb1"*/
$(function () { alert($('#tb1').val()); });

3

有谁有更好的方法?

我认为仅将脚本添加到正文中,然后将其添加到页面上的最后一个节点会更容易。这个怎么样:

function include(url) {
  var s = document.createElement("script");
  s.setAttribute("type", "text/javascript");
  s.setAttribute("src", url);
  document.body.appendChild(s);
}

我该怎么做才能使其在跨域环境中正常工作?(正在加载脚本http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js
user2284570

3

我使用了我在网上找到的另一种解决方案...该解决方案处于creativecommons之下,它会在调用函数之前检查源是否包括在内 ...

您可以在这里找到文件:include.js

/** include - including .js files from JS - bfults@gmail.com - 2005-02-09
 ** Code licensed under Creative Commons Attribution-ShareAlike License 
 ** http://creativecommons.org/licenses/by-sa/2.0/
 **/              
var hIncludes = null;
function include(sURI)
{   
  if (document.getElementsByTagName)
  {   
    if (!hIncludes)
    {
      hIncludes = {}; 
      var cScripts = document.getElementsByTagName("script");
      for (var i=0,len=cScripts.length; i < len; i++)
        if (cScripts[i].src) hIncludes[cScripts[i].src] = true;
    }
    if (!hIncludes[sURI])
    {
      var oNew = document.createElement("script");
      oNew.type = "text/javascript";
      oNew.src = sURI;
      hIncludes[sURI]=true;
      document.getElementsByTagName("head")[0].appendChild(oNew);
    }
  }   
} 

我该怎么做才能使其在跨域环境中正常工作?(从加载脚本http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js
user2284570 2014年

3

刚刚发现了YUI 3的一项重大功能(撰写本文时已在预览版中提供)。您可以轻松地将依赖项插入到YUI库和“外部”模块(您正在寻找的)中,而无需太多代码:YUI Loader

它还会在加载外部模块后回答有关正在调用的函数的第二个问题。

例:

YUI({
    modules: {
        'simple': {
            fullpath: "http://example.com/public/js/simple.js"
        },
        'complicated': {
            fullpath: "http://example.com/public/js/complicated.js"
            requires: ['simple']  // <-- dependency to 'simple' module
        }
    },
    timeout: 10000
}).use('complicated', function(Y, result) {
    // called as soon as 'complicated' is loaded
    if (!result.success) {
        // loading failed, or timeout
        handleError(result.msg);
    } else {
        // call a function that needs 'complicated'
        doSomethingComplicated(...);
    }
});

对我来说工作完美,并且具有管理依赖项的优势。有关YUI 2日历示例,请参考YUI文档。


这可能是理想的选择,除了YUI仅仅为此功能而过大。
Muhd 2012年

3

有一个新提议的ECMA标准,称为动态导入,最近已合并到Chrome和Safari中。

const moduleSpecifier = './dir/someModule.js';

import(moduleSpecifier)
   .then(someModule => someModule.foo()); // executes foo method in someModule

2

我们在工作中使用的技术是使用AJAX请求请求javascript文件,然后使用eval()返回。如果您使用的是原型库,则它们在Ajax.Request调用中支持此功能。


2

jQuery通过其.append()函数为我解决了此问题 -用于加载完整的jQuery UI包

/*
 * FILENAME : project.library.js
 * USAGE    : loads any javascript library
 */
    var dirPath = "../js/";
    var library = ["functions.js","swfobject.js","jquery.jeditable.mini.js","jquery-ui-1.8.8.custom.min.js","ui/jquery.ui.core.min.js","ui/jquery.ui.widget.min.js","ui/jquery.ui.position.min.js","ui/jquery.ui.button.min.js","ui/jquery.ui.mouse.min.js","ui/jquery.ui.dialog.min.js","ui/jquery.effects.core.min.js","ui/jquery.effects.blind.min.js","ui/jquery.effects.fade.min.js","ui/jquery.effects.slide.min.js","ui/jquery.effects.transfer.min.js"];

    for(var script in library){
        $('head').append('<script type="text/javascript" src="' + dirPath + library[script] + '"></script>');
    }

使用 -在导入jquery.js之后,在html / php / etc的头部,您只需添加一个文件,这样就可以加载整个库,并将其附加到头部...

<script type="text/javascript" src="project.library.js"></script>

2

保持其美观,简短,简单和可维护!:]

// 3rd party plugins / script (don't forget the full path is necessary)
var FULL_PATH = '', s =
[
    FULL_PATH + 'plugins/script.js'      // Script example
    FULL_PATH + 'plugins/jquery.1.2.js', // jQuery Library 
    FULL_PATH + 'plugins/crypto-js/hmac-sha1.js',      // CryptoJS
    FULL_PATH + 'plugins/crypto-js/enc-base64-min.js'  // CryptoJS
];

function load(url)
{
    var ajax = new XMLHttpRequest();
    ajax.open('GET', url, false);
    ajax.onreadystatechange = function ()
    {
        var script = ajax.response || ajax.responseText;
        if (ajax.readyState === 4)
        {
            switch(ajax.status)
            {
                case 200:
                    eval.apply( window, [script] );
                    console.log("library loaded: ", url);
                    break;
                default:
                    console.log("ERROR: library not loaded: ", url);
            }
        }
    };
    ajax.send(null);
}

 // initialize a single load 
load('plugins/script.js');

// initialize a full load of scripts
if (s.length > 0)
{
    for (i = 0; i < s.length; i++)
    {
        load(s[i]);
    }
}

此代码只是一个简短的功能示例,可能需要其他功能才能在任何(或给定)平台上提供全面支持。


2

动态模块导入已安装在Firefox 67+中

(async () => {
   await import('./synth/BubbleSynth.js')
})()

错误处理:

(async () => {
    await import('./synth/BubbleSynth.js').catch((error) => console.log('Loading failed' + error))
})()

它也适用于任何类型的非模块库,在这种情况下,可以通过旧方法在窗口对象上使用lib,但只能按需使用,这很好。

使用suncalc.js的示例,服务器必须启用CORS才能以这种方式工作!

(async () => {
 await import('https://cdnjs.cloudflare.com/ajax/libs/suncalc/1.8.0/suncalc.min.js')
 .then(function(){
   let times = SunCalc.getTimes(new Date(), 51.5,-0.1);
   console.log("Golden Hour today in London: " + times.goldenHour.getHours() + ':' + times.sunrise.getMinutes() + ". Take your pics!")
  })
})()

https://caniuse.com/#feat=es6-module-dynamic-import


1

有专门为此目的设计的脚本。

yepnope.js内置在Modernizr中,而lab.js是更优化的(但用户友好性较低的版本)。

我不建议通过jquery或prototype之类的大库来这样做-因为脚本加载器的主要优点之一是能够及早加载脚本-您不必等到jquery和所有dom元素加载之后运行检查以查看是否要动态加载脚本。


1

我编写了一个简单的模块,该模块可以自动化导入/包含JavaScript中的模块脚本的工作。尝试一下,请保留一些反馈!:)有关代码的详细说明,请参阅此博客文章:http : //stamat.wordpress.com/2013/04/12/javascript-require-import-include-modules/

var _rmod = _rmod || {}; //require module namespace
_rmod.on_ready_fn_stack = [];
_rmod.libpath = '';
_rmod.imported = {};
_rmod.loading = {
    scripts: {},
    length: 0
};

_rmod.findScriptPath = function(script_name) {
    var script_elems = document.getElementsByTagName('script');
    for (var i = 0; i < script_elems.length; i++) {
        if (script_elems[i].src.endsWith(script_name)) {
            var href = window.location.href;
            href = href.substring(0, href.lastIndexOf('/'));
            var url = script_elems[i].src.substring(0, script_elems[i].length - script_name.length);
            return url.substring(href.length+1, url.length);
        }
    }
    return '';
};

_rmod.libpath = _rmod.findScriptPath('script.js'); //Path of your main script used to mark the root directory of your library, any library


_rmod.injectScript = function(script_name, uri, callback, prepare) {

    if(!prepare)
        prepare(script_name, uri);

    var script_elem = document.createElement('script');
    script_elem.type = 'text/javascript';
    script_elem.title = script_name;
    script_elem.src = uri;
    script_elem.async = true;
    script_elem.defer = false;

    if(!callback)
        script_elem.onload = function() {
            callback(script_name, uri);
        };

    document.getElementsByTagName('head')[0].appendChild(script_elem);
};

_rmod.requirePrepare = function(script_name, uri) {
    _rmod.loading.scripts[script_name] = uri;
    _rmod.loading.length++;
};

_rmod.requireCallback = function(script_name, uri) {
    _rmod.loading.length--;
    delete _rmod.loading.scripts[script_name];
    _rmod.imported[script_name] = uri;

    if(_rmod.loading.length == 0)
        _rmod.onReady();
};

_rmod.onReady = function() {
    if (!_rmod.LOADED) {
        for (var i = 0; i < _rmod.on_ready_fn_stack.length; i++){
            _rmod.on_ready_fn_stack[i]();
        });
        _rmod.LOADED = true;
    }
};

//you can rename based on your liking. I chose require, but it can be called include or anything else that is easy for you to remember or write, except import because it is reserved for future use.
var require = function(script_name) {
    var np = script_name.split('.');
    if (np[np.length-1] === '*') {
        np.pop();
        np.push('_all');
    }

    script_name = np.join('.');
    var uri = _rmod.libpath + np.join('/')+'.js';
    if (!_rmod.loading.scripts.hasOwnProperty(script_name) 
     && !_rmod.imported.hasOwnProperty(script_name)) {
        _rmod.injectScript(script_name, uri, 
            _rmod.requireCallback, 
                _rmod.requirePrepare);
    }
};

var ready = function(fn) {
    _rmod.on_ready_fn_stack.push(fn);
};

// ----- USAGE -----

require('ivar.util.array');
require('ivar.util.string');
require('ivar.net.*');

ready(function(){
    //do something when required scripts are loaded
});

1

我在所有这些示例中迷失了,但是今天我需要从主.js加载外部.js,并且这样做:

document.write("<script src='https://www.google.com/recaptcha/api.js'></script>");

您可以看一下链接:答案
asmmahmud

1

是一个具有回调和IE支持的简单示例:

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("https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function () {

     //jQuery loaded
     console.log('jquery loaded');

});

1

我知道我对这个问题的回答有点晚,但是,这是www.html5rocks.com上的一篇很棒的文章- 深入探究脚本加载的阴暗水域

在该文章中得出的结论是,关于浏览器支持,动态加载JavaScript文件而不阻止内容呈现的最佳方法是以下方法:

考虑到您已经命名了四个脚本,script1.js, script2.js, script3.js, script4.js那么可以通过应用async = false来做到这一点:

[
  'script1.js',
  'script2.js',
  'script3.js',
  'script4.js'
].forEach(function(src) {
  var script = document.createElement('script');
  script.src = src;
  script.async = false;
  document.head.appendChild(script);
});

现在,Spec说:一起下载,全部下载后立即执行。

Firefox <3.6,Opera说:我不知道这个“异步”是什么,但是恰好发生在我按照添加顺序执行通过JS添加的脚本的过程中。

Safari 5.0说:我了解“异步”,但不了解使用JS将其设置为“假”。脚本登陆后,我将以任何顺序执行它们。

IE <10说:没有关于“异步”的想法,但是有一种使用“ onreadystatechange”的解决方法。

其他一切都说:我是你的朋友,我们将按照本书的规定进行操作。

现在,使用IE <10解决方法的完整代码:

var scripts = [
  'script1.js',
  'script2.js',
  'script3.js',
  'script4.js'
];
var src;
var script;
var pendingScripts = [];
var firstScript = document.scripts[0];

// Watch scripts load in IE
function stateChange() {
  // Execute as many scripts in order as we can
  var pendingScript;
  while (pendingScripts[0] && pendingScripts[0].readyState == 'loaded') {
    pendingScript = pendingScripts.shift();
    // avoid future loading events from this script (eg, if src changes)
    pendingScript.onreadystatechange = null;
    // can't just appendChild, old IE bug if element isn't closed
    firstScript.parentNode.insertBefore(pendingScript, firstScript);
  }
}

// loop through our script urls
while (src = scripts.shift()) {
  if ('async' in firstScript) { // modern browsers
    script = document.createElement('script');
    script.async = false;
    script.src = src;
    document.head.appendChild(script);
  }
  else if (firstScript.readyState) { // IE<10
    // create a script and add it to our todo pile
    script = document.createElement('script');
    pendingScripts.push(script);
    // listen for state changes
    script.onreadystatechange = stateChange;
    // must set src AFTER adding onreadystatechange listener
    // else we’ll miss the loaded event for cached scripts
    script.src = src;
  }
  else { // fall back to defer
    document.write('<script src="' + src + '" defer></'+'script>');
  }
}

一些技巧和缩小以后,它是362个字节

!function(e,t,r){function n(){for(;d[0]&&"loaded"==d[0][f];)c=d.shift(),c[o]=!i.parentNode.insertBefore(c,i)}for(var s,a,c,d=[],i=e.scripts[0],o="onreadystatechange",f="readyState";s=r.shift();)a=e.createElement(t),"async"in i?(a.async=!1,e.head.appendChild(a)):i[f]?(d.push(a),a[o]=n):e.write("<"+t+' src="'+s+'" defer></'+t+">"),a.src=s}(document,"script",[
  "//other-domain.com/1.js",
  "2.js"
])

我正在使用上述方法,在chrome和firefox中工作正常,但在IE浏览器中遇到了问题
Roshan先生,

1

像这样

<script>
     $(document).ready(function() {
          $('body').append('<script src="https://maps.googleapis.com/maps/api/js?key=KEY&libraries=places&callback=getCurrentPickupLocation" async defer><\/script>');
     });
</script>

1

这是一个加载JS文件的函数的简单示例。相关要点:

  • 您不需要jQuery,因此您可以最初使用它来加载jQuery.js文件
  • 它与回调异步
  • 它确保只加载一次,因为它保留了带有已加载URL记录的附件,从而避免了网络的使用
  • 与jQuery相反,$.ajax或者$.getScript您可以使用随机数,从而解决CSP的问题unsafe-inline。只需使用属性script.nonce
var getScriptOnce = function() {

    var scriptArray = []; //array of urls (closure)

    //function to defer loading of script
    return function (url, callback){
        //the array doesn't have such url
        if (scriptArray.indexOf(url) === -1){

            var script=document.createElement('script');
            script.src=url;
            var head=document.getElementsByTagName('head')[0],
                done=false;

            script.onload=script.onreadystatechange = function(){
                if ( !done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') ) {
                    done=true;
                    if (typeof callback === 'function') {
                        callback();
                    }
                    script.onload = script.onreadystatechange = null;
                    head.removeChild(script);

                    scriptArray.push(url);
                }
            };

            head.appendChild(script);
        }
    };
}();

现在,您只需通过

getScriptOnce("url_of_your_JS_file.js");

1

荒谬的单行代码,对于那些认为加载js库不应占用多于一行代码的人:P

await new Promise((resolve, reject) => {let js = document.createElement("script"); js.src="mylibrary.js"; js.onload=resolve; js.onerror=reject; document.body.appendChild(js)});

显然,如果要导入的脚本是模块,则可以使用该import(...)功能。


1

使用Promises,您可以像这样简化它。加载程序功能:

  const loadCDN = src =>
    new Promise((resolve, reject) => {
      if (document.querySelector(`head > script[src="${src}"]`) !== null) return resolve()
      const script = document.createElement("script")
      script.src = src
      script.async = true
      document.head.appendChild(script)
      script.onload = resolve
      script.onerror = reject
    })

用法(异步/等待):

await loadCDN("https://.../script.js")

用法(承诺):

loadCDN("https://.../script.js").then(res => {}).catch(err => {})

注意:有一个类似的解决方案,但是它不会检查脚本是否已经加载并每次都加载脚本。这一项检查src属性。


0

所有主要的JavaScript库(如jscript,prototype,YUI)都支持加载脚本文件。例如,在YUI中,加载核心后,您可以执行以下操作来加载日历控件

var loader = new YAHOO.util.YUILoader({

    require: ['calendar'], // what components?

    base: '../../build/',//where do they live?

    //filter: "DEBUG",  //use debug versions (or apply some
                        //some other filter?

    //loadOptional: true, //load all optional dependencies?

    //onSuccess is the function that YUI Loader
    //should call when all components are successfully loaded.
    onSuccess: function() {
        //Once the YUI Calendar Control and dependencies are on
        //the page, we'll verify that our target container is 
        //available in the DOM and then instantiate a default
        //calendar into it:
        YAHOO.util.Event.onAvailable("calendar_container", function() {
            var myCal = new YAHOO.widget.Calendar("mycal_id", "calendar_container");
            myCal.render();
        })
     },

    // should a failure occur, the onFailure function will be executed
    onFailure: function(o) {
        alert("error: " + YAHOO.lang.dump(o));
    }

 });

// Calculate the dependency and insert the required scripts and css resources
// into the document
loader.insert();

您可以看一下链接:答案
asmmahmud

0

我已经用工作示例调整了上面的一些帖子。在这里,我们也可以将css和js放在同一数组中。

$(document).ready(function(){

if (Array.prototype.contains === undefined) {
Array.prototype.contains = function (obj) {
    var i = this.length;
    while (i--) { if (this[i] === obj) return true; }
    return false;
};
};

/* define object that will wrap our logic */
var jsScriptCssLoader = {

jsExpr : new RegExp( "js$", "i" ),
cssExpr : new RegExp( "css$", "i" ),
loadedFiles: [],

loadFile: function (cssJsFileArray) {
    var self = this;
    // remove duplicates with in array
    cssJsFileArray.filter((item,index)=>cssJsFileArray.indexOf(item)==index)
    var loadedFileArray = this.loadedFiles;
    $.each(cssJsFileArray, function( index, url ) {
            // if multiple arrays are loaded the check the uniqueness
            if (loadedFileArray.contains(url)) return;
            if( self.jsExpr.test( url ) ){
                $.get(url, function(data) {
                    self.addScript(data);
                });

            }else if( self.cssExpr.test( url ) ){
                $.get(url, function(data) {
                    self.addCss(data);
                });
            }

            self.loadedFiles.push(url);
    });

    // don't load twice accross different arrays

},
addScript: function (code) {
    var oNew = document.createElement("script");
    oNew.type = "text/javascript";
    oNew.textContent = code;
    document.getElementsByTagName("head")[0].appendChild(oNew);
},
addCss: function (code) {
    var oNew = document.createElement("style");
    oNew.textContent = code;
    document.getElementsByTagName("head")[0].appendChild(oNew);
}

};


//jsScriptCssLoader.loadFile(["css/1.css","css/2.css","css/3.css"]);
jsScriptCssLoader.loadFile(["js/common/1.js","js/2.js","js/common/file/fileReader.js"]);
});

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.