设置defer属性的script标签引入的JS函数如何在HTML中调用
解决方案
方案1:将调用逻辑包裹在DOMContentLoaded事件监听中
带defer属性的脚本会在HTML解析完成后、DOMContentLoaded事件触发前执行完成,只需把body内的函数调用放到该事件的回调里,就能保证调用时函数已经被定义,不需要修改JS文件代码,改造成本最低。
修改后temp.html的body部分代码:
<body> <script> document.addEventListener('DOMContentLoaded', function() { runThisFunction('Home'); }); </script> </body>
方案2:使用全局调用队列做中转
适合存在多处需要调用defer脚本内函数的场景,不需要所有调用都套事件监听:
- 先在head最开头添加一段极短的内联脚本,定义全局调用队列:
<head> <script> // 提前定义全局调用队列 window.fnCallQueue = window.fnCallQueue || []; </script> <script src="temp.js" defer></script> <title>Defer et al</title> </head>
- 将body内的函数调用改为往队列中推送任务:
<body> <script> fnCallQueue.push(['runThisFunction', 'Home']); </script> </body>
- 只需在
temp.js末尾添加一段执行队列的逻辑,不会影响原有顶层执行逻辑:
function runThisFunction(varin) { console.log(varin); } // 新增:执行队列中所有待调用的函数 if (window.fnCallQueue) { window.fnCallQueue.forEach(([fnName, ...args]) => { if (typeof window[fnName] === 'function') { window[fnName](...args); } }); // 清空队列避免重复执行 window.fnCallQueue.length = 0; }
方案3:将内联调用脚本改为ES模块类型
type="module"的内联脚本默认自带defer效果,执行时机晚于所有带defer的普通外部脚本,不需要修改JS文件,直接调用即可:
<body> <script type="module"> runThisFunction('Home'); </script> </body>
唯一注意点是ES模块内的变量默认是局部作用域,仅调用全局挂载的函数不受影响。
内容的提问来源于stack exchange,提问作者brking
相关产品推荐
相关产品推荐

