如何推迟内联Javascript?

use*_*782 44 html javascript jquery deferred-execution

我有以下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>
Run Code Online (Sandbox Code Playgroud)

我收到一个错误,说没有定义jQuery.现在,即使我从我的内联JS代码中删除defer,它也说jQuery是未定义的.出于某种原因,我必须将jQuery插件保留在头部并保持我的JS代码内联.我的问题是:

  1. 为什么内联Javascript代码在defer属性存在时不会延迟?

  2. 有没有办法模仿我的内联Javascript代码的延迟行为?如果需要,我可以将它放在body标签的末尾.

tri*_*cot 83

具有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>
    
    Run Code Online (Sandbox Code Playgroud)

注意:请注意,在后一种情况下$(document).ready(function()不再包括,因为它将等待相同的事件(DOMContentLoaded).您可能还包括像您在最初的代码有,但随后的jQuery只会执行回调马上,这使得没有实际的区别.

  • 是的,这是肯定的。 (2认同)

Bro*_*dan 39

您可以从脚本中创建Base64 URL并将其放入src!

<script src="data:text/javascript;base64,YWxlcnQoJ0hlbGxvIHdvcmxkIScpOw=="
        defer>
</script>
Run Code Online (Sandbox Code Playgroud)

我建立了一个快速测试,看看它在行动.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>
Run Code Online (Sandbox Code Playgroud)

手动完成它有点费力,所以如果您能以某种方式(Handlebars,Angular等)编译HTML,那么这将有很大帮助.

我目前正在使用:

<script src="data:text/javascript;base64,{{base64 "alert('Hello world!');"}}"
        defer>
</script>
Run Code Online (Sandbox Code Playgroud)

  • 这太可怕了......但很棒 (38认同)
  • 不需要base64编码,只需使用:`data:text/javascript,alert('hello world')`。大多数人没有意识到 dataURL 本质上不需要编码为 base64。工作示例:https://jsbin.com/vazuruxica/edit?html,output 我建议对您的答案进行编辑:) (9认同)
  • 这超出了评估;不仅很难找到错误,还必须阅读base64 :) (3认同)
  • 太好了! (2认同)

小智 24

您还可以使用type="module"

<meta charset="utf-8">

<script type="module">
let t = document.getElementById('top');
console.log(t);
</script>

<h1 id="top">Top Questions</h1>
Run Code Online (Sandbox Code Playgroud)

https://developer.mozilla.org/docs/Web/HTML/Element/script#attr-type

  • 这应该是第一答案。 (3认同)
  • 这是无需黑客就能工作的最短解决方案,太棒了! (2认同)

Mic*_*ský 8

使用纯文本数据 URI 延迟加载 - Chrome 和 FF

#noLib #vanillaJS

建议不要在跨浏览器生产中使用

直到 MS IE 消亡,MS Edge 将采用 Chromium 开源;)

延迟脚本的唯一方法是外部文件Data_URI(不使用事件 DOMContentLoaded)

推迟

spec script#attr-defer(MDN 网络文档):“如果 src 属性不存在(即对于内联脚本),则不得使用此属性,在这种情况下它将不起作用。)”

数据_URI

规格数据_URI

使用正确的类型“text/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
})

">
Run Code Online (Sandbox Code Playgroud)

是的,这有点奇怪,但<script type="module">默认情况下被推迟,没有其他选项可以按确切顺序混合以下内容

  • 模块外部文件 -默认延迟
  • 模块内联脚本 -默认延迟
  • 外部文件 -可选择延迟
  • 内联脚本 - 只有这个hack - 据我所知(没有库/框架)


Jai*_*Jai 6

来自MDN文档:

defer
此Boolean属性设置为向浏览器指示脚本应在文档解析后但在fire之前执行DOMContentLoadeddefer属性仅应在外部脚本上使用。

这称为IIFE (立即调用函数表达式),它在DOM可用之前被执行。因此,在那种情况下jQuery是未定义的,因为它不在DOM中。