我尝试为jQuery $(document)找到等效的代码。准备好了,发现有一些不同的版本:
版本1:
function ready(fn) {
if (document.readyState != 'loading'){
fn();
} else {
document.addEventListener('DOMContentLoaded', fn);
}
}
版本2:
document.addEventListener('DOMContentLoaded', fn);
有什么区别?为什么版本1会检查document.readyState?另外,版本1是一个函数,而版本2是一个已执行的语句。那么版本1应该有一个语句吗:
ready(fn);
jQuery的文档有你的问题的答案。
jQuery.ready ():
大多数浏览器以
DOMContentLoaded
事件的形式提供类似的功能。然而,jQuery的.ready()
方法在一个重要和有用的方面有所不同:如果DOM准备好了,并且浏览器在代码调用.ready( handler )
之前触发了DOMContentLoaded
,函数处理程序仍然会被执行。相反,在事件触发后添加的DOMContentLoaded
事件侦听器永远不会执行....
所以你的版本2有上述问题。版本1即使文档已经准备好,也调用传递的函数。
不同的是,如果您添加了对ready
的调用,那么即使在DOMContentLoaded
触发之后执行脚本(更多信息请参阅document.readyState
),第一个也可以工作。第二个不会,因为事件只触发一次,所以如果脚本在此之后执行,fn
将永远不会被调用。
那么,在事件已经触发之后,脚本如何执行呢?基本上,如果它是动态添加的,而不是作为文档初始HTML的一部分。下面是几个例子:
- 在文档加载后添加的
script
元素。 一个通过动态
import()
而不是静态import
加载的模块。可能还有其他人。
版本1是一个函数,而版本2是一个已执行的语句。那么版本1应该有一个语句吗:
ready(fn);
是的,绝对正确。
我应该注意,你不需要如果 您可以控制脚本如何包含在页面中。(所以,你在库中确实需要它,但很少在应用程序/页面中。)如果您控制脚本如何包含在页面中,并且希望代码在构建DOM之后运行,那么可以使用以下几种方法(IMHO,按照最佳实践的顺序):
- 在脚本上使用
type="module"
使其成为一个模块。模块在DOM构建完成之前不会执行(它们是自动延迟的,即使是内联模块; - 在
script
标签上使用defer
(仅适用于引用文件的src
脚本标签,而不是内联脚本)。延迟脚本直到DOM构建完成才执行。 - 将
script
标签放在文档的末尾,就在结束</body>
标签之前。
如果你做任何这些事情,没有必要使用ready
(jQuery的或那些在你的问题)。