addEventListener偶发报错:页面回退后menu.htm加载失效如何解决
问题根因
- jQuery
load()方法加载menu.htm是异步操作,和页面底部硬编码的bundle.js执行时序不稳定:- 首次加载时网络耗时稍长,刚好menu.htm的DOM插入完成后bundle.js才执行,可正常绑定事件
- 页面回退时浏览器会启用往返缓存(bfcache)或menu.htm走本地缓存,异步加载时序错乱,bundle.js执行时#menu容器内还没有menu.htm的DOM节点,menu.js要绑定事件的元素不存在,就抛出
Cannot read property 'addEventListener' of null报错
- 由于无法修改bundle.js逻辑,只需调整资源加载时序,保证bundle执行前menu的DOM已完成渲染即可解决。
可行解决方案
方案1:将bundle加载逻辑放到load回调中(优先推荐)
调整脚本逻辑,等menu.htm完全加载插入DOM后再动态加载业务脚本,从根本上避免时序问题。
注意需要删掉原页面底部硬编码的vendors.js、bundle.js引入标签,避免重复执行
<head> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> </head> <body> <header class="page-header inverse"> <div class="page-header__inner"> <div id="menu" class="container"></div> </div> </header> <main>Content</main> <script> // 加载menu完成后再加载业务脚本 $("#menu").load("menu.htm", function() { // 动态加载依赖 const vendorsScript = document.createElement('script') vendorsScript.src = 'js/vendors.js' document.body.appendChild(vendorsScript) vendorsScript.onload = function() { const bundleScript = document.createElement('script') bundleScript.src = 'js/bundle.js' document.body.appendChild(bundleScript) } }); // 处理浏览器回退的bfcache场景 window.addEventListener('pageshow', function(e) { if (e.persisted) { // 清空原有内容重新加载menu $('#menu').empty().load('menu.htm', function() { // 重新加载bundle执行绑定逻辑 const bundleScript = document.createElement('script') bundleScript.src = 'js/bundle.js?' + Date.now() document.body.appendChild(bundleScript) }) } }) </script> </body>
方案2:强制menu.htm不缓存(临时兼容方案)
如果不想调整脚本加载顺序,可给menu.htm请求加时间戳参数,强制每次拉取最新内容,降低缓存导致的时序异常概率:
$("#menu").load("menu.htm?t=" + Date.now());
该方案仅解决缓存问题,仍存在异步时序异常的可能性,仅作为临时兼容使用。
内容的提问来源于stack exchange,提问作者Nevada DMV
相关产品推荐
相关产品推荐

