点击按钮动态添加脚本并调用方法遇两类问题求助
动态加载聊天脚本并调用方法的问题修复
问题场景
我希望点击按钮时动态添加聊天窗口的脚本,并调用该脚本中的方法,目前实现的代码如下:
原JavaScript代码
const callExternalScript = url => { let script script = document.querySelector(`script[src=\"${url}\"]`) if (!script) { script = document.createElement('script') script.type = 'application/javascript' script.src = url script.async = true document.body.appendChild(script) } return new Promise((res, rej) => { script.addEventListener('load', function() { res() }) script.addEventListener('error', function() { rej('error') }) }) } const handleClick = () => { callExternalScript('http://abcd.js') .then(() => { abc() // method from abcd js; }) .catch(err => { console.log(err) }) }
原HTML代码
<button onClick="handleClick()">Click Me</button>
存在的问题
- 脚本首次加载时可正常运行,但脚本已加载后再次点击按钮无法正常工作
- 无法调用
abc()方法:因为abcd.js内部会加载另一个包含该方法的脚本,当前代码未等待这个嵌套脚本加载完成就执行调用
解决方案
1. 修复重复加载后的执行问题
通过缓存已加载完成的脚本URL,避免重复绑定load事件(已加载的脚本不会再次触发load事件),直接返回已完成状态。
2. 等待嵌套脚本加载完成
新增轮询函数,检查全局目标方法是否可用,确保嵌套脚本加载完成后再执行调用,同时添加超时机制防止无限等待。
修改后的完整代码
JavaScript部分
// 缓存已加载完成的脚本URL const loadedScripts = new Set(); const callExternalScript = url => { return new Promise((res, rej) => { // 脚本已加载完成,直接resolve if (loadedScripts.has(url)) { res(); return; } let script = document.querySelector(`script[src="${url}"]`); if (!script) { script = document.createElement('script'); script.type = 'application/javascript'; script.src = url; script.async = true; document.body.appendChild(script); } // 检查脚本是否已加载完成(之前添加但未绑定事件的情况) if (script.readyState === 'complete' || script.readyState === 'loaded') { loadedScripts.add(url); res(); return; } script.addEventListener('load', function() { loadedScripts.add(url); res(); }); script.addEventListener('error', function() { rej(`加载脚本 ${url} 失败`); }); }); }; // 等待指定全局方法可用,默认超时10秒 const waitForMethod = (methodName, timeout = 10000) => { return new Promise((res, rej) => { const checkInterval = setInterval(() => { if (typeof window[methodName] === 'function') { clearInterval(checkInterval); res(); } }, 100); // 超时处理 setTimeout(() => { clearInterval(checkInterval); rej(`等待方法 ${methodName} 超时`); }, timeout); }); }; const handleClick = () => { callExternalScript('http://abcd.js') .then(() => waitForMethod('abc')) .then(() => { abc(); // 安全调用目标方法 }) .catch(err => { console.error(err); }); };
HTML部分
<button onClick="handleClick()">Click Me</button>
内容的提问来源于stack exchange,提问作者Master.Deep
相关产品推荐
相关产品推荐

