动态创建<script>标签加载外部JS后,Promise回调未执行导致无法实例化对象的问题求助
看起来你遇到的问题是动态加载外部脚本后,then里的代码没触发,导致MyObjet实例化失败对吧?我来帮你排查几个可能的原因和对应的解决办法:
1. 检查defer属性的影响
你给动态创建的<script>设置了defer,但动态创建的script标签的defer属性不会像静态插入的那样生效。浏览器对动态脚本的defer处理逻辑和静态脚本不同,而你已经通过onload监听加载完成事件,完全不需要依赖defer。建议直接去掉这个属性:
s = document.createElement("script"); // 移除这一行:s.defer = true; s.id = "test"; s.src = "myUrl/externalfile.min.js";
2. 排查脚本是否加载失败
有可能你的外部脚本根本没加载成功,导致reject被触发但你没捕获到。给onerror加个错误日志,确认是否进入了失败分支:
s.onerror = function(err) { console.error("外部脚本加载失败:", err); reject(new Error(`加载失败:${err.message}`)); };
同时检查myUrl/externalfile.min.js的路径是否正确,有没有跨域问题(比如浏览器控制台的CORS报错)。
3. 修正this的指向问题
在testMethod里调用this.loadMyScript()时,如果testMethod的调用上下文不对(比如作为按钮点击事件回调时,this指向的是按钮元素),会导致loadMyScript无法正确执行,Promise根本没启动。
解决办法:
- 如果
loadMyScript是全局函数,直接去掉this,改为loadMyScript() - 如果是对象方法,确保调用
testMethod时绑定正确的this,比如:// 调用时绑定 yourObject.testMethod.bind(yourObject)(button, objet); // 或者在testMethod里用箭头函数固定上下文 const testMethod = async (button, objet) => { return this.loadMyScript().then(() => { console.log('Buildin MyObject'); return new MyObjet(button, objet); }); };
4. 确保MyObjet是全局可访问的
如果外部脚本externalfile.min.js是模块化代码(比如用了ES模块的export),那么MyObjet不会自动挂载到window全局对象上,动态加载后你在全局作用域里就访问不到它。
解决方式二选一:
- 在外部脚本里手动暴露全局变量:
// 在externalfile.min.js末尾添加 window.MyObjet = MyObjet; - 改用动态
import加载模块(更推荐,避免全局污染):async function loadMyScript() { // 直接导入模块,获取导出的MyObjet const { MyObjet } = await import('myUrl/externalfile.min.js'); return MyObjet; } async function testMethod(button, objet) { const MyObjet = await loadMyScript(); console.log('Buildin MyObject'); return new MyObjet(button, objet); }
5. 避免重复加载脚本
如果testMethod被多次调用,会重复创建<script>标签,即使浏览器缓存了脚本,第二次加载时onload可能不会触发。可以加个缓存逻辑,确保脚本只加载一次:
let scriptLoadPromise = null; // 缓存加载Promise function loadMyScript() { if (scriptLoadPromise) return scriptLoadPromise; // 已加载中或加载完成,直接返回Promise scriptLoadPromise = new Promise((resolve, reject) => { const s = document.createElement("script"); s.id = "test"; s.src = "myUrl/externalfile.min.js"; s.onload = () => { console.log("脚本加载完成"); resolve(); }; s.onerror = (err) => { console.error("脚本加载失败", err); reject(err); scriptLoadPromise = null; // 失败后允许重试 }; document.head.appendChild(s); }); return scriptLoadPromise; }
先从检查脚本加载状态和this指向开始排查,这些是最常见的问题哦!
内容的提问来源于stack exchange,提问作者ouzo

