将脚本放在底部的两种不同方式 - 有什么区别
Two different ways of putting the script at the bottom - what are the differences?
以下两种解决方案有什么区别?特别是,是否有充分的理由偏爱 2 而不是 1。(注意:请假定要加载的脚本的名称已知。问题只是关于在给定情况下创建一个最小脚本来加载脚本是否有价值)
1 - 底部脚本
<html>
<body>
...
...
<script src='myScript.js'></script>
</body>
</html>
2 - 底部的脚本加载外部脚本
<html>
<body>
...
...
<script>
// minimal script to load another script
var script = document.createElement('script');
script.src = 'myScript.js'
document.body.appendChild(script);
</script>
</body>
</html>
第二个的一个重要功能是它允许浏览器立即完成页面解析,而无需等待脚本加载。这是因为第一个示例允许脚本使用 document.write
来更改 <script>
标记周围的解析状态,而第二个示例则不允许。
现在,我们知道它位于页面底部,因此没有任何重要内容需要解析,但这仍然是一个重要的区别。直到解析完成,浏览器才会触发流行的DOMContentLoaded
事件。在方法 1 中,事件在脚本加载并执行后触发。在方法 2 中,事件在脚本开始加载之前触发。
以下是一些示例。在这些演示中,DOMContentLoaded
侦听器将背景颜色更改为黄色。我们尝试加载一个需要 3 秒才能加载的脚本。
- http://jsfiddle.net/35ccs/
- http://jsfiddle.net/VtwUV/
(编辑:也许jsfiddle不是举办这些演示的最佳场所。在加载缓慢加载脚本之前,它不会显示结果。请务必在加载后再次单击"运行",以查看会发生什么情况。
选择最适合您的应用程序的方法。如果您知道需要在 DOMContentLoaded
之前运行脚本,请使用方法 1。否则,方法2在大多数情况下非常好。
1. 底部脚本
当您使用"同步"脚本标记时,它将阻止浏览器呈现页面,直到加载和执行脚本。此方法具有以下效果:
-
无论您将脚本标记放在何处,浏览器都无法触发 DOMContentLoaded,直到脚本下载并执行。
-
将这样的脚本标记放在底部只能确保浏览器在被脚本阻止之前已经呈现了所有内容。
2. 底部脚本加载外部脚本
当您使用 JavaScript 注入脚本标记时,它将创建一个不会阻止浏览器的"异步"脚本标记。此方法具有以下效果:
- 无论您将生成脚本标记的 JavaScript 代码放在何处,浏览器都会在可用时立即执行它,而不会阻止页面。DOMContentLoaded在应该触发时触发;无论脚本是否已下载/执行。
第二种方法具有以下优点:
- 注入脚本标签的脚本可以放置在任何位置,包括文档头。
- 脚本不会阻止渲染。
- DOMContentLoaded 事件不等待脚本。
第二种方法有以下缺点:
- 不能在此类脚本中使用
document.write
。如果这样做,此类语句可能会擦除文档。 - 异步执行并不意味着浏览器已完成页面解析。请记住脚本在可用时立即执行。
- 不保证执行顺序。示例:如果使用注入的脚本标签加载"library.js"和"use-library.js",则"use-library.js"可以在"library.js"之前加载和执行。
说了这么多,还有另一种加载脚本的方法,有三种变体:
<script src="myScript.js" async></script>
<script src="myScript.js" defer></script>
<script src="myScript.js" async defer></script>
关于Steve Souders的工作:他提出了6种加载脚本而不阻塞的技术。HTML5中引入的async
和defer
属性涵盖了Script DOM Element和Script Defer技术,它们的浏览器支持足以让您担心其他技术。
这两种初始化脚本的方法基本相同,尽管如果可以直接输入结果,则没有理由使用第二种方法。但是,您可以将第二个示例包装在 $(document).ready()
方法中,例如,这会导致某种延迟加载效果。这基本上意味着页面将首先加载,页面加载完成后它将加载脚本。或者,当然,您可以创建一个以这种方式初始化某个脚本的方法。当您有一个仅在某些情况下使用的大型脚本时,它很有用。这将阻止加载它,除非你需要它,从而减少整体加载时间。
这不是对您的问题的直接回答,但无论如何很高兴知道。
第二种方法有时用作库回退。
例如,您从Google CDN加载jQuery。 但是,如果由于任何原因失败,请从您自己的本地副本加载jQuery。
以下是流行的HTML5样板建议这样做的方式:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.11.0.min.js"><'/script>')</script>
第一种方法意味着脚本标记是硬编码的。第二种方法使用 JavaScript 将脚本标记动态添加到页面底部。第二种方法的好处是,如果需要修改脚本标记,可以添加其他逻辑。也许您可能希望根据区域性、浏览器或您可以在 JavaScript 中确定的其他因素加载不同的脚本文件。第二种方法还会导致加载 JavaScript 文件而不阻止网页其余部分的加载。在方法一中,页面将在到达脚本标记时停止加载,加载 JavaScript 文件,然后完成页面其余部分的加载。由于此标签位于页面底部,因此不会产生太大影响。
如果你使用 JavaScript创建 Windows 应用商店应用,则建议使用第一种方法,因为这将允许应用对 JavaScript 文件进行字节码缓存,从而使其加载速度更快。
- 全局变量和全局对象的属性之间有什么区别吗
- 为什么这在IE中的工作方式与在Firefox中不同
- 在AngularJS应用程序中使用封装指令和路由的推荐方式是什么
- 什么'这是JS中以下定义方式的区别
- 用两种方式保存对象,有什么区别
- 这两种用 JavaScript 编写原型函数的方式有什么区别?
- 当我以以下方式在控制器中使用 gridapi 时有什么区别
- 调用事件侦听器 - 两种方式之一起作用,有什么区别
- Chrome 和 Firefox 以及浏览器在解析字符串的方式上有什么区别吗?
- 我让用户将脚本加载到网页中的方式是否有区别
- D3这两种数据绑定方式有什么区别
- 都是'sync'event和Backbone.sync以某种方式连接在一起——两者之间有什么区别
- 对象定义有两种方式-有什么区别
- 这两种在javascript中编写函数的方式之间的区别
- 在JS中这三种声明方法的方式有什么区别吗?
- 在coffeescript(在Rails中)中调用函数的两种方式的区别
- 两种承诺链实现方式的区别
- 在Javascript中向对象添加属性的两种方式的区别
- 在JavaScript中以不同方式定义类的区别
- 将脚本放在底部的两种不同方式 - 有什么区别