我有以下HTML代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/blazy/1.8.2/blazy.min.js" defer></script>
<script src="https://code.jquery.com/jquery-2.1.4.min.js" integrity="sha256-8WqyJLuWKRBVhxXIL1jBDD7SDxU936oZkCnxQbWwJVw=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lightbox2/2.9.0/js/lightbox.min.js" defer></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous" defer></script>
<!-- 26 dec flexslider js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/flexslider/2.6.3/jquery.flexslider.min.js" defer></script>
<script defer>
(function($) {
$(document).ready(function() {
//do something with b-lazy plugin, lightbox plugin and then with flexslider
});
})(jQuery);
</script>
</head>
<body>
</body>
</html>
我收到错误,说没有定义jQuery。现在,即使我从我的内联JS代码中删除defer,它也说jQuery是未定义的。出于某种原因,我必须将jQuery插件保留在头部并保持我的JS代码内联。我的问题是:
为什么当defer
属性存在时,内联Javascript代码是否会被延迟?
有没有办法模仿我的内联Javascript代码的延迟行为?如果需要,我可以将它放在body标签的末尾。
答案 0 :(得分:71)
defer
属性的脚本按照指定的顺序加载,但不在文档本身之前加载。由于defer
标记对script
标记没有影响,除非它们也具有src
属性,因此执行的第一个脚本是您的内联脚本。所以当时jQuery还没有加载。
您可以通过以下两种方式解决此问题:
将您的内联脚本放在.js
文件中,并使用src
属性引用它(除了您已经拥有的defer
属性),或
让您的内联脚本等待文档和加载的延迟脚本。发生这种情况时,DOMContentLoaded
事件将会触发:
<script>
window.addEventListener('DOMContentLoaded', function() {
(function($) {
//do something with b-lazy plugin, lightbox plugin and then with flexslider
})(jQuery);
});
</script>
注意:请注意,在后一种情况下$(document).ready(function()
不再包括在内,因为它会等待同一事件(DOMContentLoaded
)。您可以仍然像原始代码一样包含它,但是jQuery只会立即执行回调 ,这没有实际意义。
答案 1 :(得分:30)
您可以从脚本中创建Base64 URL并将其放入src!
<script src="data:text/javascript;base64,YWxlcnQoJ0hlbGxvIHdvcmxkIScpOw=="
defer>
</script>
我建立了一个快速测试,看看它在行动。
如果Hello world!
正在运行,您应该会看到defer
的提醒:
<script defer>
alert('Why no defer?!?');
</script>
<!-- alert('Hello world!'); -->
<script src="data:text/javascript;base64,YWxlcnQoJ0hlbGxvIHdvcmxkIScpOw=="
defer></script>
<script>
alert('Buh-bye world!');
</script>
&#13;
手动操作有点费力,所以如果您能以某种方式(Handlebars,Angular等)编译HTML,那么这将有很大的帮助。
我目前正在使用:
<script src="data:text/javascript;base64,{{base64 "alert('Hello world!');"}}"
defer>
</script>
答案 2 :(得分:5)
来自MDN docs:
<强>延迟强>
此布尔属性设置为向浏览器指示在解析文档之后但在触发DOMContentLoaded
之前要执行脚本。 defer属性只能用于外部脚本。
这称为IIFE (立即调用的函数表达式),它在DOM可用之前执行。因此,在这种情况下jQuery
未定义,因为它不在DOM中。
答案 3 :(得分:1)
有一个常识,您应该使用<script src=".." async defer>
(或从JS进行操作时在分配script.async = true
之前设置src
)和/或将脚本放在最底端页面上的内容,以便尽可能快地将尽可能多的页面加载并呈现给用户。
defer.js(请注意:我是该脚本的作者)是用纯JavaScript编写的,从而使延迟加载其他内容更加快捷和高效。您可以有效地延迟任何javascript文件以及内联脚本块。
如果您的页面只是经过JavaScript增强的HTML页面,那么仅使用<script async>
就可以了。浏览器需要花费一些时间来解析和执行这些脚本,并且每次UI更改都可能重新排列您的布局,使您的加载速度更加缓慢,没有人喜欢盯着空白的白纸;用户没有耐心,会很快离开。
在各种情况下,使用async
或defer
不能提供比defer.js更快的页面速度。
答案 4 :(得分:1)
您也可以使用type="module"
:
<meta charset="utf-8">
<script type="module">
let t = document.getElementById('top');
console.log(t);
</script>
<h1 id="top">Top Questions</h1>
https://developer.mozilla.org/docs/Web/HTML/Element/script#attr-type
答案 5 :(得分:0)
#noLib #vanillaJS
建议不要在跨浏览器产品中使用
直到MS IE死亡并且MS Edge将采用Chromium开源;)
spec script#attr-defer (MDN web docs):“如果不存在src属性(例如,对于内联脚本),则不得使用此属性,在这种情况下,它将无效。)”
规范Data_URI
使用正确的类型“文本/ javascript” ,根本不需要 base64 ...;)
使用纯文本,因此您可以使用简单的内容:
<script defer src="data:text/javascript,
//do something with b-lazy plugin, lightbox plugin and then with flexslider
lightbox.option({
resizeDuration: 200,
wrapAround: true
})
">
是的,这有点奇怪,但是默认情况下会延迟<script type="module">
,没有其他选择以完全顺序混合以下内容:
答案 6 :(得分:0)
我检查了所有建议的解决方案,但都有其缺点。所以我自己发明了。
将此内联脚本放入您的 head 标记或 body 标记的开头之后:
<script>var Defer = []; document.addEventListener('DOMContentLoaded', function() { while (Defer.length) Defer.shift().call(); }); </script>
这个 liner 将收集所有您想要延迟的内联脚本,并在文档完全加载后立即分别运行它们。现在,只要您需要延迟运行内联脚本,只需像这样注册它:
<script>
alert('This alert will show immediately.');
Defer.push(function() {
alert('This alert will show only after document is loaded.');
// You can use anything which is not loaded yet, like jQuery
$(".selector").doSomeJqueryStuff();
});
// You can use it as many times as you like and in any place of your DOM.
Defer.push(function() {
// Any inline code you want to defer
});
</script>
此内联脚本仅在文档加载后运行。这意味着您可以运行内联 jQuery 脚本,让您的 jQuery 停留在 DOM 的末尾。