如何在外部 CDN 脚本失败时异步回退? (async/defer)
How to asynchronously fall back when external CDN script fails? (async/defer)
我有这些脚本,我想 download/execute 异步地防止页面呈现阻塞:
Bootstrap依赖于jQuery,所以必须按照这个顺序执行。这就是我使用 defer
的原因,但我的问题也适用于 async
。
如何异步回退到我自己的 jQuery 或 Bootstrap 托管版本,或任何 CDN 托管的脚本?
我已经看到 this related question on Whosebug,但这些解决方案不起作用,因为:
- 它依赖于
document.write
,不能用于async
/defer
脚本;或:
- 它不会立即执行回退脚本,当 jQuery 无法加载时会导致问题,并且依赖于 jQuery 的其他脚本会在 jQuery 回退执行之前加载。
我尝试了以下方法,但这也导致了上面描述的问题 #2:
<script src="failing external CDN script" defer onerror="
var script = document.createElement('script');
script.async = false;
script.src = 'my own hosted version the script';
document.body.appendChild(script);
"></script>
I have these scripts that I want to download/execute asynchronously to prevent page render blocking
最简单的方法就是将它们放在页面末尾,就在结束 </body>
标记之前。他们不 render-block 在那里,你可以简单地做回退:
<script src="jQuery CDN"></script>
<script>
if (typeof jQuery === "undefined") {
// ...add your local version instead...
}
</script>
您在评论中说过,PageSpeed 会抱怨 </body>
之前的 script
标签,如果它们没有 defer
。恕我直言,它没有(请注意 link 到 code.jquery.com
是故意破坏的):
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="favicon.png">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-12">
Content here, turns green on click
</div>
</div>
</div>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<script src="https://code.jquery.com/jquery-2.2.4.mn.js"></script>
<script>
if (typeof jQuery === "undefined") {
document.write('<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"><\/script>');
}
</script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script>
$(".col-md-12").on("click", function() {
$(this).css("color", "green");
});
</script>
</body>
</html>
从 PageSpeed 获得 100/100(如果您正确托管它——压缩等)。
现在,如果我在底部有 CSS link
,我也会在顶部有内联 CSS 来设置 above-the-fold 内容的样式。 (但我可能不会打扰,我只是将 link
放在顶部并接受命中。我只将它放在该示例的底部,因为 PageSpeed 将 JS 和 CSS 放在一起它关于该主题的警告,我想证明 </body>
之前的 script
不会触发该错误...)
但是如果你想使用 defer
,你必须监听你问题中显示的 error
事件。当然,这意味着您必须推迟添加依赖于 jQuery 的脚本,直到您从原始脚本或其替换中获得 load
,因为您不能 insert 到管道中。例如:
<script src="failing external CDN script" defer onerror="
var script = document.createElement('script');
script.async = false;
script.onload = addDependencies;
script.src = 'my own hosted version the script';
document.body.appendChild(script);
" onload="addDependencies()"></script>
...其中 addDependencies
根据脚本为事物添加 script
标签。
我有这些脚本,我想 download/execute 异步地防止页面呈现阻塞:
Bootstrap依赖于jQuery,所以必须按照这个顺序执行。这就是我使用 defer
的原因,但我的问题也适用于 async
。
如何异步回退到我自己的 jQuery 或 Bootstrap 托管版本,或任何 CDN 托管的脚本?
我已经看到 this related question on Whosebug,但这些解决方案不起作用,因为:
- 它依赖于
document.write
,不能用于async
/defer
脚本;或: - 它不会立即执行回退脚本,当 jQuery 无法加载时会导致问题,并且依赖于 jQuery 的其他脚本会在 jQuery 回退执行之前加载。
我尝试了以下方法,但这也导致了上面描述的问题 #2:
<script src="failing external CDN script" defer onerror="
var script = document.createElement('script');
script.async = false;
script.src = 'my own hosted version the script';
document.body.appendChild(script);
"></script>
I have these scripts that I want to download/execute asynchronously to prevent page render blocking
最简单的方法就是将它们放在页面末尾,就在结束 </body>
标记之前。他们不 render-block 在那里,你可以简单地做回退:
<script src="jQuery CDN"></script>
<script>
if (typeof jQuery === "undefined") {
// ...add your local version instead...
}
</script>
您在评论中说过,PageSpeed 会抱怨 </body>
之前的 script
标签,如果它们没有 defer
。恕我直言,它没有(请注意 link 到 code.jquery.com
是故意破坏的):
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="favicon.png">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-12">
Content here, turns green on click
</div>
</div>
</div>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<script src="https://code.jquery.com/jquery-2.2.4.mn.js"></script>
<script>
if (typeof jQuery === "undefined") {
document.write('<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"><\/script>');
}
</script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script>
$(".col-md-12").on("click", function() {
$(this).css("color", "green");
});
</script>
</body>
</html>
从 PageSpeed 获得 100/100(如果您正确托管它——压缩等)。
现在,如果我在底部有 CSS link
,我也会在顶部有内联 CSS 来设置 above-the-fold 内容的样式。 (但我可能不会打扰,我只是将 link
放在顶部并接受命中。我只将它放在该示例的底部,因为 PageSpeed 将 JS 和 CSS 放在一起它关于该主题的警告,我想证明 </body>
之前的 script
不会触发该错误...)
但是如果你想使用 defer
,你必须监听你问题中显示的 error
事件。当然,这意味着您必须推迟添加依赖于 jQuery 的脚本,直到您从原始脚本或其替换中获得 load
,因为您不能 insert 到管道中。例如:
<script src="failing external CDN script" defer onerror="
var script = document.createElement('script');
script.async = false;
script.onload = addDependencies;
script.src = 'my own hosted version the script';
document.body.appendChild(script);
" onload="addDependencies()"></script>
...其中 addDependencies
根据脚本为事物添加 script
标签。