You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何为jQuery的$.getMultiScripts添加Deferred保证脚本顺序加载?

解决jQuery多脚本顺序加载的Firefox兼容问题

嘿,我懂你的困扰——原有的$.getMultiScripts函数是同时发起所有脚本的请求,浏览器(尤其是Firefox)会根据请求完成的先后顺序执行脚本,完全不管你传入数组的顺序。要实现严格按顺序加载执行,我们得改成串行加载:等前一个脚本加载并执行完,再去加载下一个。

正确的实现方式

这里用$.Deferred结合数组的reduce方法来构建链式调用,完美保证顺序:

$.getMultiScripts = function(arr, path) {
  // 处理路径前缀,可选参数
  path = path || '';
  if (path && path.slice(-1) !== '/') {
    path += '/';
  }

  // 用reduce链式创建Deferred,实现串行加载
  return arr.reduce(function(prevDeferred, scriptUrl) {
    return prevDeferred.then(function() {
      // 加载当前脚本,返回Deferred对象
      return $.ajax({
        cache: true,
        url: path + scriptUrl,
        dataType: 'script'
      });
    });
  }, $.Deferred().resolve()); // 初始Deferred直接resolve,启动链式流程
};

// 使用示例
var script_arr = [ 'myscript1.js', 'myscript2.js', 'myscript3.js' ];
$.getMultiScripts(script_arr, '/mypath/')
  .done(function() {
    console.log('所有脚本按顺序加载完成!');
  })
  .fail(function(error) {
    console.error('某个脚本加载失败:', error);
  });

关键点解释

  • 串行依赖的核心reduce方法会遍历脚本数组,每次都在前一个脚本加载完成的then回调里发起下一个请求,从根本上保证了顺序。
  • 初始Deferred:我们用$.Deferred().resolve()作为reduce的初始值,确保第一个脚本能立刻开始加载。
  • 路径兼容:保留了原函数的路径前缀功能,处理了路径末尾是否带斜杠的细节。
  • 错误处理:加上fail回调能捕获加载失败的情况,比原函数更健壮。

更简洁的版本(用$.getScript)

因为$.getScript本身就是$.ajax的封装(默认dataType: 'script'),所以可以简化代码:

$.getMultiScripts = function(arr, path) {
  path = path || '';
  if (path && path.slice(-1) !== '/') {
    path += '/';
  }

  return arr.reduce(function(prev, script) {
    return prev.then(function() {
      return $.getScript(path + script, { cache: true });
    });
  }, $.Deferred().resolve());
};

为什么你之前的修改没生效?

你之前尝试给所有脚本用同一个Deferred并直接resolve,这其实还是在并行发起所有请求,没有建立任何依赖关系,自然没法保证顺序。串行加载的核心是让每个请求都等待前一个完成,而不是同时触发。

这种方式在所有浏览器(包括Firefox)都能稳定工作,特别适合脚本之间有依赖关系的场景。

内容的提问来源于stack exchange,提问作者Aldee

火山引擎 最新活动