jsdelivr.net挂了,前端如何动态的切换cdn呢?

_韩奕迅
  • 33

jsdelivr.net挂了,前端如何动态的切换cdn呢?

回复
阅读 2k
3 个回答
<script>
// 可实现多个cdn失效切换
var cdnArr =[{
css:'//unpkg.com/bootstrap@3.3.7/dist/css/bootstrap.css',
js:'//unpkg.com/bootstrap@3.3.7/dist/js/bootstrap.min.js'}];

function autoCDN(){
      if(!cdnArr.length) return;
      var cdn=cdnArr.shift();

      var l=document.createElement('link');
      l.href=cdn.css;
      l.onerror=function(){autoCDN(this);};
      document.head.appendChild(l);

      var s=document.createElement('script');
      s.src=cdn.js;
      s.onerror=function(){autoCDN(this);};
      document.body.appendChild(s);
}
</script>
<script 
src="//cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js" 
onerror="autoCDN();" 
></script>

下面是我的一些想法

你可以这么写

<script src="https://cdn.staticfile.org/vue/2.6.14/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js"></script>

解决重复加载,可以这么写的(目前我是这么用的

<script src="https://cdn.staticfile.org/vue/2.6.14/vue.min.js"></script>
<script>
      window.Vue ||
        document.write(
          '<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js"><\/script>'
        );
</script>

当然这还是写死的,同时两个CDN挂了还是出事(应该不会吧),或许还能这样

<script>
    // const arr = "https://cdn.staticfile.org/vue/2.6.14/vue.min.js";
    const arr = fetch('你的服务器'); // 伪代码, 动态获取CDN地址,可以通过后端配置
    let node = document.createElement('script');
    node.src = arr;
    document.head.appendChild(node);
    node = null;
</script>

在官方issue里看到一个有意思的仓库,瞄了一下还没使用过
https://github.com/EtherDream...

四五年前折腾过前端资源高可用,19年的时候写过一篇分享,其实蛮简单的,但是细节蛮多的,想做的深入一些,还需要做好监控,和运维团队合作。

言归正传,简单的场景使用 onerror 方式能够解决问题,但是一旦业务复杂,资源量比较大的时候,就需要针对方法进行封装,或者采用模块加载器动态加载、以及需要针对构建工具产物进行调整。

先来聊聊简单场景的解决方案:

    <script>
        function loadOthers(resource) {
            var script = document.createElement('script');
            script.src = resource.src.replace('demo-cdn.lab.io','demo.cdn2.io');
            document.head.appendChild(script);
        }
    </script>
    <script src="//demo-cdn.lab.io/assets/app.js" onerror="loadOthers(this)"></script>

为了进一步防患未然,我们一般不会只准备一套 CDN 候选,那处理方式还需要进一步调整

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        function loadResource(links, fnSuccess, fnError) {
            var script = document.createElement('script');
            script.onerror = function () {
                document.head.removeChild(script);
                fnError();
            };
            script.onload = fnSuccess
            script.src = links.shift();
            document.head.appendChild(script);
        }

        function autoSwitch(resourceList) {
            var resource = resourceList.shift();
            loadResource([resource], function (success) {
                console.log('loaded');
            }, function (err) {
                console.log('load error')
                autoSwitch(resourceList);
            });
        }
    </script>
</head>
<body>
    <script>
        var resourceList = [
            'http://demo-cdn.lab.io/assets/app.js',
            'http://demo.cdn2.io/assets/app.js',
            'assets/app.js',
        ];

        autoSwitch(resourceList);
    </script>
</body>
</html>

现代一些的应用,为了解决性能问题,我们一般会使用资源加载器,如何在这个场景下保证资源高可用呢?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>

    <script src="assets/require-v2.3.6.min.js"></script>

    <script>
        function autoSwitch(resourceList) {
            var resource = resourceList.shift();
            requirejs([resource], function (success) {
                console.log('loaded');
            }, function (err) {
                console.log('load error')
                autoSwitch(resourceList);
            });
        }
    </script>
</head>
<body>
    <script>
        var resourceList = [
            'http://demo-cdn.lab.io/assets/app.js',
            'http://demo.cdn2.io/assets/app.js',
            'assets/app.js',
        ];

        autoSwitch(resourceList);
    </script>
</body>
</html>

讲到这里,资源自动加载几乎讲完了,但是实际上还存在一些额外的坑。
比如结合当前最流行的构建工具 webpack 使用,图片资源是一次性写死的,需要支持动态化等等。

最后,附上19年分享的内容: https://soulteary.com/2019/05...

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏