浏览器环境下如何在指定脚本加载完成后调用其函数(仅关注目标脚本)
问题描述
我的HTML中有两个script标签:
<script src="first.js"></script> <script src="second.js"></script>
其中first.js是一个大型库文件,加载完成后会提供funcFromFirstJs函数。我希望在该函数就绪时调用它,但有时first.js还未加载完成,second.js就已开始执行。
目前我采用递归检查的方式实现:
// second.js function callIfReady() { if (typeof funcFromFirstJs === 'function') { funcFromFirstJs(); } else { // 等待一段时间后再次调用callIfReady() } }
请问是否有更优的实现方式?我了解window的load事件(会在包括图片在内的所有资源加载完成后触发),也了解document的DOMContentLoaded事件(在标签加载完成后触发,但可能早于内容加载完毕)。由于first.js是库文件,我不想在其末尾添加自定义代码,仅希望等待first.js完全加载完成后,再执行second.js中的对应代码,完全不关心图片或其他脚本的加载进度,因此不想使用window的load事件。
更优实现方案
1. 监听目标脚本的load事件
这是最精准匹配需求的方案,直接追踪first.js的加载状态:
- 如果能修改HTML中的script标签,直接添加
onload事件:
<script src="first.js" onload="funcFromFirstJs()"></script> <script src="second.js"></script>
- 若无法修改HTML,可在
second.js中获取目标脚本标签并绑定事件:
// second.js const firstScript = document.querySelector('script[src="first.js"]'); // 先检查脚本是否已加载完成 if (firstScript.readyState === 'complete' || firstScript.readyState === 'loaded') { funcFromFirstJs(); } else { firstScript.addEventListener('load', () => { funcFromFirstJs(); }); }
这种方式只关注first.js的加载状态,完全不受其他资源影响。
2. 用MutationObserver替代递归轮询
比起定时器递归检查,MutationObserver是更高效的监听方式,全局变量一就绪就触发执行:
// second.js const observer = new MutationObserver(() => { if (typeof funcFromFirstJs === 'function') { funcFromFirstJs(); observer.disconnect(); // 执行完成后停止监听 } }); observer.observe(window, { propertyFilter: ['funcFromFirstJs'] // 仅监听目标变量的变化 }); // 先做一次即时检查,避免脚本已提前加载完成的情况 if (typeof funcFromFirstJs === 'function') { funcFromFirstJs(); observer.disconnect(); }
没有定时器的延迟和多余性能开销,比递归轮询更优雅。
3. 动态加载脚本(可选方案)
如果允许调整脚本加载逻辑,可以在second.js中主动控制first.js的加载顺序:
// second.js function loadScript(src, callback) { const script = document.createElement('script'); script.src = src; script.onload = callback; // 可添加重复加载判断,避免重复插入脚本 if (!document.querySelector(`script[src="${src}"]`)) { document.body.appendChild(script); } } // 加载first.js完成后执行目标函数 loadScript('first.js', () => { funcFromFirstJs(); });
这种方式彻底掌控脚本加载顺序,但需要注意避免重复加载first.js。
内容的提问来源于stack exchange,提问作者Morris
相关产品推荐
相关产品推荐

