题 RequireJS:CDN失败时的本地回退


在我的骨干应用程序中,我需要为每个所需文件提供一个后备,如果提供它们的CDN失败。

我试过覆盖 require.onError 像这样:

require.onError = function (err) {
    if (err.requireType === 'timeout') {
        var url = err.requireModules;

        if (!!~url.indexOf("jquery/"))
            console.warn("CDN timed out, falling back to local jQuery.js")
            require(["libs/jquery"]);
            return;
        if (!!~url.indexOf("jqueryui/"))
            console.warn("CDN timed out, falling back to local jQueryUI.js")
            require(["libs/jqueryui"]);
            return;
        if (!!~url.indexOf("underscore"))
            console.warn("CDN timed out, falling back to local underscore.js")
            require(["libs/underscore"]);
            return;
        if (!!~url.indexOf("backbone"))
            console.warn("CDN timed out, falling back to local backbone.js")
            require(["libs/backbone"]);
            return;
    }
}

问题是这将异步加载回退文件。我需要按顺序加载这些文件,就像我使用的原始require语句一样 order! 插入。

随着被覆盖 onError:当CDN无法加载时,后备加载开始,但不等待。这提出了一个问题,因为脚本是根据它们的依赖性来加载的。这是我的原创 require 声明,这取决于CDN:

require([
    "order!http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js",
    "order!http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js",
    "order!http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js",
    "order!http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min.js",
    "order!utils/date",
    "order!core/core",
    "order!core/errors",
    "order!core/constants"
], function() {
    ...
}

29
2017-08-22 13:02


起源


两个CDN并不可怕,它们平均每天只能失败一次,最多只有一分钟的窗口,并且是免费的。无论如何,我觉得这是一个有待解决的问题。即使您拥有完美的CDN,也始终保持良好的后备,以保持用户体验。你能推荐任何其他CDN吗? - Austin
我知道你来自哪里,但我不能建议为我们公司购买这样的东西,而没有提供足够的证据证明我已经尝试了一切来使当前的系统工作。此外,我对任何编程专长感兴趣,我可以看到这个特定的解决方案对许多人有用,因为许多开发人员(特别是自由职业者)不使用付费CDN。 - Austin
CDN现在很便宜(每月2美元到3美元)......我使用的是AccuWebHosting.Com CDN,从未经历任何停机。好吧,如果一台服务器在CDN中出现故障,内容会立即从最近的可用下一个POP传送......并且在一个好的CDN中通常有40到50个POP ... - AccuWebHosting.Com
我不明白这个问题的惊愕。流行的CDN +后备是一种常见的情况,并且提供了许多用户甚至不必下载JS的优势,因为它已经在浏览器中缓存。无论如何,其他异步加载器可以解决这个现实世界的问题。 OP只是问如何用requirejs来解决它。 - numbers1311407
@ numbers1311407,这是我的立场。 - Austin


答案:


您使用的是什么版本的RequireJS?您似乎可能希望将jQuery的回退配置为配置中的路径,然后将jQuery设置为对需要它的其他模块的依赖。如果您使用〜> 2.0,那么(未经测试):

// in your requirejs config
requirejs.config({
    //To get timely, correct error triggers in IE, force a define/shim exports 
    // check.
    enforceDefine: true,
    paths: {
        jquery: [
            'http://somecdn.com/jquery.min', // your cdn
            'lib/jquery' // your fallback
        ],
        jqueryui: "http://somecdn.com/jquery-ui.min.js"
    },
    shim: {
      jqueryui: ['jquery']
    }
});

// then in your requires
require([jquery, jqueryui, foo, bar], function($) {
    // stuff
});

他们谈论如何做到这一点 在维基。如果您不使用v2.x,那么也有一种处理方法。

如果所有模块都配置为指定自己的依赖项,则不必担心 order! 指令要么。


57
2017-08-22 14:25



打败我2分钟,但是,这是我的答案。 - Austin
哈哈没有。我认为这是大约15秒。 - numbers1311407
运行优化器后如何管理?它是否为html中的已排除文件添加了脚本标记? - sidonaldson
@sidonaldson回退路径用于处理可能不可用的外部资源,以及AFAIK, 根据文件,优化器仅适用于本地资源。我相信如果你想捆绑外部资源,你首先要下载它。如果我错了请任何人纠正我;我一直喜欢像browserify这样的解决方案。 - numbers1311407
你测试过这个吗?对于我的配置,如果路径是表单 [CDN, local],找不到CDN脚本(Wi-Fi关闭),然后是那些 shim.deps 参考脚本似乎在选择本地回退之前运行: requirejs.config({ baseUrl: 'bower_components', paths: { /* JS */ 'jquery': ['//code.jquery.com/jquery-1.10.2.min', 'jquery/jquery.min'], 'bootstrap': 'bootstrap/dist/js/bootstrap.min' }, shim: { 'bootstrap': { deps: ['jquery'] } } } }); 给 Uncaught Error: Bootstrap requires jQuery - Dean Radcliffe


我找到了RequireJS 2.x.x中提供的问题的解决方案。需要这个解决方案,所以反过来,RequireJS添加了一个 paths 反对他们的配置。如果CDN失败,这将为CDN提供回退功能。

还应该指出的是 order! 插件已在Require 2.0中弃用,所以我还需要使用 shim 用于定义依赖关系的对象。这实际上是一个非常有趣的想法。

这是我的新require.config:

require.config({
    urlArgs: "ts="+new Date().getTime(), // disable caching - remove in production
    paths: {
        jquery: [
            "http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min",
            "libs/jquery"
        ],
        jqueryui: [
            "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min",
            "libs/jqueryui"
        ],
        underscore: [
            "http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min",
            "libs/underscore"
        ],
        backbone: [
            "http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min",
            "libs/backbone"
        ]
    },
    shim: {
        'jqueryui': ['jquery'],
        'underscore': ['jquery'],
        'backbone': ['underscore'],
        'core/core': ['underscore'],
        'core/errors': ['core/core'],
        'core/constants': ['core/core']
    }
});

19
2017-08-22 14:25