如何让head中的异步脚本及Promise完成后再加载页面?
如何让异步脚本执行完成后再加载页面?
问题背景
我有一个外部异步脚本需要在页面加载前执行完成。根据了解,页面默认会先完成head标签内容的解析(同步脚本会阻塞解析),但异步脚本不会阻塞页面加载,导致页面内容先渲染出来。比如示例中,"testing"文本先显示蓝色,3秒后才变为粉色,而我希望只看到粉色文本。如果无法实现完全阻塞页面加载,想知道如何在异步脚本完成后、页面开始加载前重定向到其他页面。
示例代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style>p {color: blue}</style> <script> // 模拟3秒后 resolve 的 Promise async function fakePromise() { return new Promise(function(resolve, reject) { setTimeout(resolve, 3000); }); } // 等待 Promise 完成后插入样式 async function applyStyle() { await fakePromise(); var styleElement = document.createElement('style'); var css = "p { color: pink !important; }"; styleElement.appendChild(document.createTextNode(css)); document.head.insertBefore(styleElement, document.head.firstChild); } applyStyle(); // 实际项目中此脚本会是带 src 属性的外部脚本 </script> </head> <body> <p>testing</p> </body> </html>
解决方案
1. 完全阻塞页面解析,直到异步操作完成
利用同步脚本结合await阻塞执行,再通过document.write重写整个页面,确保原页面内容不会提前渲染:
<script> async function fakePromise() { return new Promise(resolve => setTimeout(resolve, 3000)); } async function init() { await fakePromise(); // 执行异步逻辑(比如插入自定义样式) const customCss = "p { color: pink !important; }"; // 重写整个页面 document.write(` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style>p {color: blue}</style> <style>${customCss}</style> </head> <body> <p>testing</p> </body> </html> `); document.close(); } init(); </script>
原理:同步脚本会阻塞HTML解析,await会等待Promise完成后才执行document.write,浏览器会重新解析输出的HTML,因此只会显示最终的粉色文字。
2. 隐藏页面直到异步完成(更友好的方案)
避免阻塞解析,先隐藏页面内容,异步完成后再显示:
- 在head添加初始隐藏样式:
<style> body { display: none; } </style>
- 修改脚本逻辑:
<script> async function fakePromise() { return new Promise(resolve => setTimeout(resolve, 3000)); } async function applyStyle() { await fakePromise(); const styleElement = document.createElement('style'); styleElement.textContent = "p { color: pink !important; }"; document.head.prepend(styleElement); // 异步完成后显示页面 document.body.style.display = 'block'; } applyStyle(); </script>
效果:页面一开始为空白,3秒后直接显示粉色文字,不会出现蓝色闪烁。
3. 异步完成后立即重定向
如果需要在异步完成后重定向,确保在页面渲染前触发:
<script> async function fakePromise() { return new Promise(resolve => setTimeout(resolve, 3000)); } async function redirectAfterAsync() { await fakePromise(); // 立即执行重定向 window.location.href = '/your-target-page.html'; } redirectAfterAsync(); </script>
注意:若浏览器已开始渲染body,可能会有短暂闪烁,建议结合页面隐藏的方式使用。
内容的提问来源于stack exchange,提问作者user8758206
相关产品推荐
相关产品推荐

