.html文件防止script脚本缓存的三种方法
作者:柯尔茶
场景
我们有一个工具库通过 script 放在了全局中,它会提供一个带有许多方法的全局对象 gTool。就像下面这样:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <script type="text/javascript" src="https://xxxx/common/tool.min.js"></script> // [!code hl] </head> <body> <div id="app"><!--app-html--></div> <script type="module" src="/src/main.ts"></script> </body> </html>
然后我们就可以在 main.ts 里能使用 gTool.jumpLink 方法啦。
gTool.jumpLink({})
问题
但是现在有这样一个问题,由于一些原因,我们经常需要修改 gTool 的代码然后上传更新 cdn。但是用户通过 html 文件访问的 gTool 链接实际上还是缓存的,根本不会去请求服务器,也就导致用户的 gTool 版本可能过低 bug 没有被修复。
所以现在问题就是如何禁止缓存。
方法
这里我尝试了 3 个方法
1 创建 script 标签并 appendChild 到 body
最终我选择了这种方案,满足需求并且上线后没有问题。
可以使用 js 动态创建 script 节点并插入到 dom 中去。 但是需要注意动态创建的 script 脚本是异步的,不会阻塞浏览器向下执行 js。
下面这段代码,永远都是 'body 执行' 先于 'tool 脚本执行' 打印。这样就导致获取不到全局的 gTool 对象,也就导致报错了。
<!DOCTYPE html> <html> <head> <script> var htmlScriptScript = document.createElement('script') htmlScriptScript.type = 'text/javascript' htmlScriptScript.src = 'https://xxxx/common/tool.min.js?a=' + Math.random() htmlScriptScript.onload = function () { console.error('tool 脚本执行') } document.head.appendChild(htmlScriptScript) </script> </head> <body> <div id="app"><!--app-html--></div> <script> console.error('body 执行') </script> <script type="module" src="/src/main.ts"></script> </body> </html>
为了保证 gTool 加载完成后才向下执行脚本,我们可以自己写一个阻塞函数。如下:
<!DOCTYPE html> <html> <head> <script> var htmlScriptScript = document.createElement('script') htmlScriptScript.type = 'text/javascript' htmlScriptScript.src = 'https://xxxx/common/tool.min.js?a=' + Math.random() htmlScriptScript.onload = function () { window.gTool = gTool } document.head.appendChild(htmlScriptScript) </script> </head> <body> <div id="app"><!--app-html--></div> <script> + async function main() { + function awaitTool() { + return new Promise(resolve => { + const interval = setInterval(() => { + if (window.gTool) { + clearInterval(interval) + resolve(null) + } + }, 50) + }) + } + await awaitTool(); + // other code + } + main() </script> <script type="module" src="/src/main.ts"></script> </body> </html>
main()
函数会每隔 50ms 去检查 window 上是否有 gTool 对象,有就说明 gTool 脚本已经加载完了,可以继续往下执行了,否则就继续递归执行 main()
,知道 gTool 脚本加载完毕。
2 在地址后加一个随机参数
并不是很好的解决方案。
这种方法虽然可行,但是每次都需要发版。因为发版需要走流程审核,而且有发版次数限制。
下面两种引入方式都是一样的,只不过第二种每次重新打包的时候会自动刷新时间戳。
<script type="text/javascript" src="https://xxxx/common/tool.min.js?time=1124112341"></script> // [!code hl] <!-- 或者 --> <script type="text/javascript" src="https://xxxx/common/tool.min.js?time=<%=Math.random()%>"></script>
3 document.write()
这种方法不行。
使用 document.write API 来防止 .html 文件缓存 script 脚本。
在 MDN 里写了,从 Chrome 55 开始,Chrome(可能)不会运行通过 document.write() 注入的 <script>
,以防止使用 2G 连接的用户找不到 HTTP 缓存。所以这种方法用来动态注入 <script>
脚本根本不可行。
<script> document.write("<script src='https://xxxx/common/tool.min.js?rnd=" + Math.random() + "'></s " + " cript> ") </script>
以上就是.html文件防止script脚本缓存的三种方法的详细内容,更多关于.html防止script缓存的资料请关注脚本之家其它相关文章!