模块类型Script元素重新插入DOM后不执行JS,如何重新运行代码?
如何重新运行已加载过的JavaScript模块代码?
经测试发现,若JavaScript模块已从同一地址加载过,即便对应的<script>元素已从DOM中移除,浏览器也不会重新运行该模块代码。点击Remove按钮移除<script>元素后,再次创建并插入同地址的模块类型<script>元素时,代码不会执行,请问有什么方法可以重新运行该模块的代码?
问题复现代码
HTML代码
<script type="module" src="./t.js"></script> <script> function add(){ const s = document.createElement('script'); s.type='module'; s.src='./t.js'; document.body.prepend(s) } function remove(){ document.querySelector(`script[src='./t.js']`).remove(); } </script> <button onclick="remove()">Remove</button> <button onclick="add()">Add</button>
t.js代码
// t.js import * from 'example.com/blah'; window.alert('Hi')
可行的解决方法
1. 给模块URL添加唯一查询参数(缓存击穿)
浏览器会将带有不同查询参数的URL判定为不同资源,因此每次添加模块时,给URL拼接一个唯一值(比如时间戳、随机字符串),就能触发浏览器重新加载并执行模块:
function add(){ const s = document.createElement('script'); s.type='module'; // 拼接当前时间戳作为唯一参数 s.src=`./t.js?=${Date.now()}`; document.body.prepend(s) }
注意:这种方式会重新下载模块文件,若模块体积大或需要频繁执行,可能带来性能损耗。
2. 使用动态import()函数(推荐方案)
动态import允许你在需要时手动加载模块,且每次调用都会重新执行模块内的逻辑(浏览器仍会缓存模块文件,但代码逻辑会重新运行)。
首先修改t.js,把需要重复执行的逻辑封装成可导出的函数:
// t.js import * from 'example.com/blah'; export function runModule() { window.alert('Hi'); }
然后在主脚本中通过动态import调用该函数:
async function add(){ // 每次调用都会加载模块并执行指定函数 const module = await import('./t.js'); module.runModule(); }
这种方法无需操作DOM中的<script>元素,还能灵活控制执行的逻辑,是更优的解决方案。
3. 手动重置模块执行状态
如果必须依赖<script>元素的方式,可以自行维护模块的执行状态,同时修改模块内部逻辑,将可重复执行的部分抽离出来,通过全局变量或其他方式触发重新执行。不过这种方法复杂度较高,不如前两种直接。
内容的提问来源于stack exchange,提问作者David Min
相关产品推荐
相关产品推荐

