如何让页面元素在异步用户凭证验证完成后再加载?
问题
我希望在网站任意页面加载前验证用户凭证,因此将包含异步函数(用于发起验证API调用)的脚本放置在HTML文档顶部,但发现当脚本执行异步操作时,页面其他元素仍会优先加载,即使脚本已放在顶部。相关代码如下:
HTML代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Bebas+Neue&display=swap" rel="stylesheet"> <link href="home.css" rel="stylesheet"> <script src="../isUserLogged.js"></script> <!-- 这里是我提到的验证脚本 --> <script src="home.js" defer></script> <!-- 即使加了DEFER,这个脚本还是提前运行 --> <title>Caderneta</title> </head> <body> <div class="header"> <p id="home-txt" class="header-txt">Home</p> <p id="user-txt" class="header-txt">Olá, Nome!</p> </div> <div class="content"> <iframe src="../notebooks/notebooks.html"></iframe> </div> </body> </html>
isUserLogged.js代码
// Local Storage const token = localStorage.getItem("token"); async function isUserSessionValid() { const options = { method: "POST", headers: { "Content-Type": "application/json", "Authorization": token }, body: token }; try { const response = await fetch("http://localhost:8080/teachers/get-by-token", options); if(response.ok) { sessionStorage.setItem("user", JSON.stringify(await response.json())); return true; } } catch(e) { } alert("Erro ao validar sessão, faça login ou tente novamente mais tarde."); return false; } async function validateUserSession() { if(token != null) { if(await isUserSessionValid()) { return; } } localStorage.clear(); sessionStorage.clear(); location.replace("../login/login.html"); } validateUserSession();
请问如何实现仅在所有异步函数执行完成后再加载页面元素?
解决方案
方案1:先隐藏页面,验证通过后再显示
这是最快捷的实现方式,通过CSS先隐藏页面内容,验证完成后再显示:
- 在
home.css中添加隐藏样式:
body { display: none; }
- 修改
validateUserSession函数,验证通过后解除隐藏:
async function validateUserSession() { if(token != null) { if(await isUserSessionValid()) { // 验证通过,显示页面 document.body.style.display = 'block'; return; } } localStorage.clear(); sessionStorage.clear(); location.replace("../login/login.html"); }
可选:可以在隐藏期间添加加载动画,避免用户看到空白页面。
方案2:动态渲染页面内容
完全避免页面内容提前加载,验证通过后再将内容插入DOM:
- 修改HTML,只保留空的容器和内容模板:
<body> <div id="app-container"></div> <template id="page-content"> <div class="header"> <p id="home-txt" class="header-txt">Home</p> <p id="user-txt" class="header-txt">Olá, Nome!</p> </div> <div class="content"> <iframe src="../notebooks/notebooks.html"></iframe> </div> </template> </body>
- 更新
validateUserSession函数,验证通过后渲染模板:
async function validateUserSession() { if(token != null) { if(await isUserSessionValid()) { // 克隆模板内容并插入容器 const template = document.getElementById('page-content'); const content = template.content.cloneNode(true); document.getElementById('app-container').appendChild(content); // 手动加载依赖脚本(比如home.js) const script = document.createElement('script'); script.src = 'home.js'; document.body.appendChild(script); return; } } localStorage.clear(); sessionStorage.clear(); location.replace("../login/login.html"); }
这种方式能确保iframe等资源不会提前请求,完全受控于验证结果。
方案3:让依赖脚本等待验证完成
如果需要保留原有HTML结构,可通过全局Promise让其他脚本等待验证结束:
- 修改
isUserLogged.js,暴露验证Promise:
// 将验证函数的Promise暴露到全局 window.sessionValidation = validateUserSession();
- 修改
home.js,等待验证完成后再执行逻辑:
(async function() { // 等待验证完成 await window.sessionValidation; // 这里写原本home.js的业务逻辑 })();
同时去掉HTML中home.js的defer属性,避免脚本提前执行。
内容的提问来源于stack exchange,提问作者C410lol
相关产品推荐
相关产品推荐

