动态加载 JavaScript 文件

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

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

主流 JavaScript 库如何实现这一点(Prototype、 jQuery 等) ?这些工具是否将多个 JavaScript 文件合并到一个脚本文件的单个可重新发布的“构建”版本中?或者他们做任何辅助“库”脚本的动态加载?

这个问题的补充: 在加载动态包含的 JavaScript 文件之后,是否有办法处理这个事件? Prototype 对于文档范围的事件有 document.observe:

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

脚本元素的可用事件是什么?

203757 次浏览

下面是我找到的一些示例代码... 有人有更好的方法吗?

  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);
}

所有主要的 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();

我做的基本上和你做亚当的一样,只是做了一点小小的修改,以确保我是在附加 head元素来完成这项工作。我只是创建了一个 include函数(下面的代码)来处理脚本和 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 element = null;
switch( type ){
case 'text/javascript' :
element = document.createElement( 'script' );
element.type = type;
element.src = url;
break;
case 'text/css' :
element = document.createElement( 'link' );
element.rel = 'stylesheet';
element.type = type;
element.href = url;
break;
}
    

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

有人有更好的办法吗?

我认为将脚本添加到主体比将其添加到页面的最后一个节点更容易。这样吧:

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

我们在工作中使用的技术是使用 AJAX 请求请求 javascript 文件,然后 eval ()返回。如果您正在使用原型库,它们在 Ajax 中支持这一功能。请求电话。

我使用了 更简单的版本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-less 版本:

<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>

我使用了我在网上找到的另一个解决方案... 这个是在 Creative Commons 下面,它是 检查在调用函数之前是否包含源代码..。

你可以在这里找到文件: 包括.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);
}
}
}

您可以使用 原型机动态创建脚本元素:

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 请求提取脚本,并在全局级别对脚本进行求值。

如果使用 Prototype,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);
}
};

刚刚发现在 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(...);
}
});

对我来说非常有效,并且有管理依赖关系的优势。

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>

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

这种方法比其他方法有一个优势,那就是您有一个内置的回调函数(以保证在依赖代码运行之前加载脚本) ,并且您可以控制缓存。

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

Yepnope.js 是内置在 Modernizr 的,而 实验室是一个更优化的版本(但用户友好性较差)。

我不推荐通过 jquery 或者 Prototype 这样的大型库来做这件事——因为脚本加载器的主要好处之一就是能够提前加载脚本——你不应该等到 jquery 和所有的 dom 元素都加载完毕之后才检查你是否想要动态加载脚本。

又一个很棒的答案

$.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

Javascript 中没有导入/包含/需求,但是有两种主要的方法可以达到你想要的效果:

你可以用一个 AJAX 调用加载它,然后使用 eval。

这是最简单的方法,但是由于 Javascript 的安全设置,它仅限于您的域,并且使用 eval 会打开 bug 和黑客攻击的大门。

2-使用 HTML 中的脚本 URL 添加一个脚本元素。

绝对是最好的死法。您甚至可以从外部服务器加载该脚本,而且在使用浏览器解析器评估代码时它是干净的。您可以将 script元素放在网页的 head元素中,或者放在 body的底部。

这里讨论并说明了这两种解决方案。

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

这意味着,如果直接使用这些技巧,那么在要求加载新加载的代码之后的下一行就不能使用它,因为它仍然在加载。

例如: my _ love _ 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 event 在加载脚本时运行回调函数。因此,您可以将使用远程库的所有代码放在回调函数中。例如:

function loadScript(url, callback)
{
// adding the script element 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
});

我编写了一个简单的模块,可以自动导入/包含 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
});

如果需要加载 SYNC脚本,则需要将脚本文本直接添加到 HTML HEAD 元素。添加它将触发 异种加载。要从外部文件同步加载脚本文本,请使用 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()); });

保持它漂亮、短小、简单、易于维护! : ]

// 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]);
}
}

这段代码只是一个简短的函数示例,可以需要额外的特性功能来完全支持任何(或给定)平台。

我迷失在所有这些样品,但今天我需要加载一个外部。来自我的主要。Js 和我做了这个:

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

这里的 是一个简单的带有回调和 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');


});

我知道我的回答对于这个问题来说有点晚,但是,这里有一篇很棒的 Www.html5rocks.com-深入到脚本加载的浑水中文章。

在这篇文章中,我们得出结论,在浏览器支持方面,动态加载 JavaScript 文件而不阻碍内容呈现的最佳方式是以下方式:

考虑到你有四个脚本命名为 script1.js, script2.js, script3.js, script4.js,然后你可以做它与 应用异步 = 错误:

[
'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);
});

现在,说明书上说: 一起下载,一下载就按顺序执行。

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

Safari 5.0说: 我理解“异步”,但不理解用 JS 将其设置为“ false”。你的剧本一落地,我就会执行无论什么顺序。

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"
])

像这样的事..。

<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>

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

  • 您不需要 jQuery,因此最初可以使用它来加载 jQuery.js 文件
  • 它与回调是异步的
  • 它确保只加载一次,因为它保持一个包含已加载 URL 记录的封装,从而避免使用网络
  • 与 jQuery$.ajax$.getScript相反,您可以使用 nonce,从而解决 CSPunsafe-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");

有一个新的 ECMA 标准叫做 动态输入,最近被整合到 Chrome 和 Safari 中。

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


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

对于那些认为加载 js 库只需要一行代码的人来说,这是一个荒谬的一行程序

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(...)函数。

动态 模组导入到 Firefox 67 +

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

错误处理:

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

它也适用于任何类型的非模块库,在这种情况下,旧的方法是在 window.self对象上使用库,但是只能根据需要使用,这很好。

例如使用 Suncalc.js,服务器必须有 一个 href = “ https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS”rel = “ nofollow noReferrer”> CORS 启用才能这样工作!

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

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

我已经调整了一些上述职位与工作示例。 在这里,我们也可以在同一个数组中给出 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"]);
});

有了承诺,你就可以像这样简化它。 装载机功能:

  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 的财产。

对于那些喜欢说俏皮话的人:

import('./myscript.js');

你可能会得到一个错误,比如:

从原始数据库访问“ http://..../myscript.js”的脚本 “ http://127.0.0.1”已被 CORS 政策阻止: 不 请求的 资源。

在这种情况下,你可以回到:

fetch('myscript.js').then(r => r.text()).then(t => new Function(t)());

尽管我非常喜欢 JQuery 方法的灵活性,但 JavaScript 方法并不复杂,只是需要对您已经使用的内容进行一些小的调整..。 下面是我如何动态加载 JS (只在需要时) ,并在执行依赖于它们的脚本之前等待它们加载。

JavaScript 方法

//Create a script element that will load
let dynamicScript = document.createElement('script');


//Set source to the script we need to load
dynamicScript.src = 'linkToNeededJsFile.js';


//Set onload to callback function that depends on this script or do inline as shown below
dynamicScript.onload = () => {


//Code that depends on the loaded script should be here


};


//append the created script element to body element
document.body.append(dynamicScript);

使用 JS 还有其他方法可以实现这一点,但是,我更喜欢这种方法,因为它需要每个开发人员都具备的基本 JS 知识。

这不是答案的一部分,但是这里有一个我更喜欢的 JQuery 版本,它可以用于已经包含 JQuery 的项目:

$.getScript('linkToNeededJsFile.js', () => {


//Code that depends on the loaded script should be here


});

更多关于 JQuery 选项 给你的信息

这个函数使用记忆。并且可以多次调用,而且加载和运行同一个脚本两次没有冲突。而且它的解析速度不会比实际加载脚本的速度快(就像在 @ radulle应答中一样)。

const loadScript = function () {
let cache = {};
return function (src) {
return cache[src] || (cache[src] = new Promise((resolve, reject) => {
let s = document.createElement('script');
s.defer = true;
s.src = src;
s.onload = resolve;
s.onerror = reject;
document.head.append(s);
}));
}
}();

请注意函数表达式后面的括号()。

并行加载脚本:

Promise.all([
loadScript('/script1.js'),
loadScript('/script2.js'),
// ...
]).then(() => {
// do something
})

可以对 动态加载样式表使用相同的方法。