如何使用 jQuery $.getScript() 方法包含多个 js 文件

IT技术 javascript jquery html promise
2021-01-25 15:47:47

我正在尝试将 javascript 文件动态包含到我的 js 文件中。我对它做了一些研究,发现 jQuery $.getScript() 方法是一种理想的方法。

// jQuery
$.getScript('/path/to/imported/script.js', function()
{
    // script is now loaded and executed.
    // put your dependent JS here.
    // what if the JS code is dependent on multiple JS files? 
});

但是我想知道这种方法是否可以一次加载多个脚本?我之所以这么问是因为有时我的 javascript 文件依赖于多个 js 文件。

先感谢您。

6个回答

答案是

您可以使用 promisegetScript()并等待所有脚本加载完毕,例如:

$.when(
    $.getScript( "/mypath/myscript1.js" ),
    $.getScript( "/mypath/myscript2.js" ),
    $.getScript( "/mypath/myscript3.js" ),
    $.Deferred(function( deferred ){
        $( deferred.resolve );
    })
).done(function(){
    
    //place your code here, the scripts are all loaded
    
});

小提琴

ANOTHER FIDDLE

在上面的代码中,添加一个 Deferred 并在里面解析它$()就像在 jQuery 调用中放置任何其他函数一样$(func)就像,它与

$(function() { func(); });

即它等待 DOM 准备好,因此在上面的示例中,$.when等待所有脚本加载等待DOM 准备好,因为$.Deferred调用在 DOM 准备好回调中解析。


对于更通用的用途,一个方便的功能

可以像这样创建一个接受任何脚本数组的实用程序函数:

$.getMultiScripts = function(arr, path) {
    var _arr = $.map(arr, function(scr) {
        return $.getScript( (path||"") + scr );
    });
        
    _arr.push($.Deferred(function( deferred ){
        $( deferred.resolve );
    }));
        
    return $.when.apply($, _arr);
}

可以这样使用

var script_arr = [
    'myscript1.js', 
    'myscript2.js', 
    'myscript3.js'
];

$.getMultiScripts(script_arr, '/mypath/').done(function() {
    // all scripts loaded
});

路径将被添加到所有脚本的前面,并且也是可选的,这意味着如果数组包含完整的 URL,也可以这样做,并且一起省略路径

$.getMultiScripts(script_arr).done(function() { ...

参数、错误等。

顺便说done一句,请注意回调将包含许多与传入的脚本匹配的参数,每个参数代表一个包含响应的数组

$.getMultiScripts(script_arr).done(function(response1, response2, response3) { ...

其中每个数组将包含类似[content_of_file_loaded, status, xhr_object]. 我们通常不需要访问这些参数,因为无论如何脚本都会自动加载,而且大多数时候done回调是我们真正想要知道所有脚本都已加载的全部内容,我只是为了完整性而添加它,以及在极少数情况下需要访问加载文件中的实际文本,或者需要访问每个 XHR 对象或类似内容时。

此外,如果任何脚本加载失败,将调用失败处理程序,并且不会加载后续脚本

$.getMultiScripts(script_arr).done(function() {
     // all done
}).fail(function(error) {
     // one or more scripts failed to load
}).always(function() {
     // always called, both on success and error
});
对于无法使其正常工作的任何人,请确保您的 JS 文件中没有解析错误,即首先测试它们是否在 <script> 标签中正确加载。jQuery.getScript() 会将这些错误视为加载失败,并且将调用 .fail() 而不是 .done()。@宋涛Z。
2021-03-16 15:47:47
很抱歉接受晚了。有时你的方式仍然不太奏效。不知道是什么原因。我试图一次合并四个脚本文件。$.when($.getScript(scriptSrc_1), $.getScript(scriptSrc_2), $.getScript(scriptSrc_3), $.getScript(scriptSrc_4), $.Deferred(function(deferred) { $(deferred.resolve); })).done(function() { ... })
2021-03-19 15:47:47
这是因为在 jQuery 中默认关闭 ajax 中的缓存,打开它并删除查询字符串 do :$.ajaxSetup({ cache: true });但这也可能影响您不想缓存的其他 ajax 调用,文档中有更多关于此的内容getScript,甚至还有一些关于创建名为 cachedScript 的缓存 getScript 函数的方法。
2021-03-29 15:47:47
延迟对象与允许您加载多个脚本并在它们全部完成后执行功能的Promise没有任何关系。它只是检查 $() 是否已准备好,如果是,则进行解析,换句话说,它在执行任何代码之前检查 DOM 是否已准备好,就像 document.ready 一样,我找到了一个很好的附加示例Promise在线获取在代码中具有延迟 DOM 就绪功能的 getScript,并决定保留它,因为它听起来是个好主意。
2021-03-31 15:47:47
谢谢你的好回答。你介意解释一下为什么要$.Deferred(function( deferred ){$( deferred.resolve );})在这里添加吗?
2021-04-02 15:47:47

我实现了一个简单的函数来并行加载多个脚本:

功能

function getScripts(scripts, callback) {
    var progress = 0;
    scripts.forEach(function(script) { 
        $.getScript(script, function () {
            if (++progress == scripts.length) callback();
        }); 
    });
}

用法

getScripts(["script1.js", "script2.js"], function () {
    // do something...
});
出于某种原因,这个比伊曼纽尔的要好。这也是一个非常透明的实现。
2021-03-13 15:47:47
我使用的是没有“when”功能的旧版 JQuery。但这个答案有帮助!有效!谢谢!
2021-03-14 15:47:47
@satnam 谢谢:)!最佳答案对某些人(包括我)不起作用,所以我发布了这个解决方案。而且看起来简单多了。
2021-03-19 15:47:47

在前一个的回调中加载后续所需的脚本,例如:

$.getScript('scripta.js', function()
{
   $.getScript('scriptb.js', function()
   {
       // run script that depends on scripta.js and scriptb.js
   });
});
@Roi 和其他任何人:如果我确实需要以特定顺序加载脚本,那么从根本上说,这种方法有什么问题?因此,promise 替代方案带来了什么好处?
2021-03-14 15:47:47
这种方法肯定会按顺序下载脚本,从而减慢最终执行的时间?
2021-03-22 15:47:47
几乎总是应该避免瀑布。getScript 带有一个Promise......你可以使用 $.when 来监听Promise何时解决。
2021-03-23 15:47:47
正确,@Jimbo - 公平地说;它比过早执行更可取。:)
2021-03-28 15:47:47
@IfediOkonkwo 这在需要串联时确实有效,但原版操作刚刚提到他想要一次倍数(其中,这将是一种反模式)。尽管如此,如果我想要它们串联,我会编写一个循环函数,我可以将数组传递给它。深嵌套很快就会变得混乱。
2021-04-06 15:47:47

有时需要按特定顺序加载脚本。例如 jQuery 必须在 jQuery UI 之前加载。此页面上的大多数示例并行(异步)加载脚本,这意味着无法保证执行顺序。如果没有排序,如果两者都成功加载但顺序错误y,则依赖的脚本x可能会中断。

我提出了一种混合方法,它允许顺序加载依赖脚本 + 可选的并行加载 +延迟对象

/*
 * loads scripts one-by-one using recursion
 * returns jQuery.Deferred
 */
function loadScripts(scripts) {
  var deferred = jQuery.Deferred();

  function loadScript(i) {
    if (i < scripts.length) {
      jQuery.ajax({
        url: scripts[i],
        dataType: "script",
        cache: true,
        success: function() {
          loadScript(i + 1);
        }
      });
    } else {
      deferred.resolve();
    }
  }
  loadScript(0);

  return deferred;
}

/*
 * example using serial and parallel download together
 */

// queue #1 - jquery ui and jquery ui i18n files
var d1 = loadScripts([
  "https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.min.js",
  "https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/i18n/jquery-ui-i18n.min.js"
]).done(function() {
  jQuery("#datepicker1").datepicker(jQuery.datepicker.regional.fr);
});

// queue #2 - jquery cycle2 plugin and tile effect plugin
var d2 = loadScripts([
  "https://cdn.rawgit.com/malsup/cycle2/2.1.6/build/jquery.cycle2.min.js",
  "https://cdn.rawgit.com/malsup/cycle2/2.1.6/build/plugin/jquery.cycle2.tile.min.js"

]).done(function() {
  jQuery("#slideshow1").cycle({
    fx: "tileBlind",
    log: false
  });
});

// trigger a callback when all queues are complete
jQuery.when(d1, d2).done(function() {
  console.log("All scripts loaded");
});
@import url("https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/blitzer/jquery-ui.min.css");

#slideshow1 {
  position: relative;
  z-index: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<p><input id="datepicker1"></p>

<div id="slideshow1">
  <img src="https://dummyimage.com/300x100/FC0/000">
  <img src="https://dummyimage.com/300x100/0CF/000">
  <img src="https://dummyimage.com/300x100/CF0/000">
</div>

两个队列中的脚本将并行下载,但每个队列中的脚本将依次下载,确保有序执行。瀑布图:

脚本的瀑布图

一旦脚本加载到内存中,我们不需要在HTML中添加脚本标签吗?
2021-03-19 15:47:47

使用yepnope.jsModernizr(包括 yepnope.js as Modernizr.load)。

更新

只是为了跟进,这是您当前使用 yepnope 的一个很好的等价物,显示了对多个脚本的依赖关系:

yepnope({
  load: ['script1.js', 'script2.js', 'script3.js'],
  complete: function () {
      // all the scripts have loaded, do whatever you want here
  }
});
这是新的,老实说,我不明白为什么需要它。按照最近更改列表后面的文档进行操作,您将看到更常规的用法。
2021-03-16 15:47:47
+1; 值得注意的是,这与$.getScript. 这是一个大问题。
2021-03-17 15:47:47
谢谢。我可以yepnope.injectJs( scriptSource )在我的 javascript 文件的开头使用多个,就像<script>在 html 文件中包含标签一样吗?
2021-03-18 15:47:47
yepnope.js 现在已弃用
2021-03-19 15:47:47