我理解HTML中 <script async> 的概念:
不过我对一件事有点困惑。有些人说,通过async加载的JS可能与DOM无关。
我想知道,实际应该怎么编写这个JS文件?它真的完全不能使用DOM吗?
我知道async的原理,但不知道其中的JS文件到底长成什么样。能否给出一个能够与 <script async> 配合良好的JS示例?
有些人说,通过async加载的JS可能与DOM无关。
是的,但要强调“可能”这一点,因为 async 脚本 可以 使用DOM,它只是需要一些初始入口点逻辑来确保安全,因为脚本的第一行 可能 在任何 <body> HTML/DOM可用之前就会执行——或者它 可能 在DOM加载的任意时刻运行,因此由于无法保证浏览器文档的DOM状态,这意味着脚本需要以 防御性 编写。
所以放在一个 async <script> 元素中的JS 可以 使用DOM,但 脚本必须先检查 document.readyState 首先——并且根据当前的 readyState,要么立即继续执行——要么必须安排自己在 DOMContentLoaded 发生时或之后再运行。
例如:
MyAsyncLoadedScript.js:
// (This is a plain ol' JS, with top-level code. No modules, no UMD, no AMD, no require(), no imports, etc).
if( document.readyState === 'loading' ) {
// Document is not ready yet (i.e. it is *not* yet safe to manipulate the DOM, excepting objects like `document` and `window`).
// ...so we cannot safely run this script's main function yet.
// ...so schedule it to run on DOMContentLoaded using addEventListener:
document.addEventListener( 'DOMContentLoaded', theRestOfTheScriptProgram );
// However, if this script depends on all external resources (images, other scripts, etc) being fully loaded before it runs, then use the `window` 'load' event instead of 'DOMContentLoaded'.
// See https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
// window.addEventListener( 'load', theRestOfTheScriptProgram );
}
else if( document.readyState === 'complete' ) {
// The document (the DOM and all resources) is fully loaded already, i.e. the 'load' event already fired.
// ...so it's safe to immediately run the main function synchronously:
theRestOfTheScriptProgram();
}
else /* implicit: document.readyState === 'interactive' */ {
// The 'interactive' state sits in-between 'loading' and 'complete', from 'DOMContentLoaded' until 'load'.
// ...so if the script does not depend on all external resources (images, videos, etc) being already-loaded, then it's safe to synchronously run the main function here:
theRestOfTheScriptProgram();
}
function theRestOfTheScriptProgram() {
// Inside this function, it's safe to manipulate the DOM.
// For example, `document.querySelectorAll` will behave predictably.
}