我想在加载网站的任何页面之前验证用户凭据,因此我在每个 HTML 文档的顶部放置了一个脚本。但是这个脚本特别具有异步函数(因为它发送 API 调用进行验证),并且我注意到,当必须执行某些异步函数时(在这个特定脚本内部),其他元素会在此脚本之前加载,即使我将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> <!--This is the script that I mentioned-->
<script src="home.js" defer></script> <!--This script is running before even with "DEFER" annotation-->
<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();
在所有异步函数完成后,我可以对刚刚加载的元素做什么?
根据文档,具有
defer
属性的脚本将在解析文档之后执行,但不是在渲染文档之后执行。原因,为什么你感觉之前执行的脚本是渲染延迟。
正如评论中提到的@Phil
<body>
<div id='loader' class='loader'>Loading...</div>
<!-- Rest of your code -->
</body>
.loader {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
async function validateUserSession() {
if(token != null) {
if(await isUserSessionValid()) {
const loader = document.getElementById('loader');
loader.style.display = 'none';
return;
}
}
localStorage.clear();
sessionStorage.clear();
location.replace("../login/login.html");
}
首先你需要了解什么是“推迟”。 Defer 类似于将常规脚本放在页面底部。这意味着,延迟脚本将始终在窗口的
defer
事件之前触发。之前的常规脚本中的任何 Promise 或异步脚本都不会停止进一步解析 HTML。
DOMContentLoaded
意味着您可以完全看到带有图像等占位符的初始 HTML 文本,而不保证 DOMContentLoaded
、
img
、动态
video
、
stylesheet
和
link
脚本。一旦所有这些都加载完毕,就会触发一个单独的
async
事件。所以,
load
在
load
之后。
页面自带的异步脚本给你0保证。它们必须在
DOMContentLoaded
之前开火,但有些也可以在 load
之前开火。
DOMContentLoaded
属性本质上将这些资产的下载卸载到单独的线程。
此时你有3个选择:
制作一个专门的 HTML 页面,仅运行
async
isUserLogged.js
响应:
Content-type
,类似于登录页面。
使用 css 以可视方式隐藏元素,直到异步函数返回 true 或登录详细信息。
text/html
请注意,现在两个脚本都
<head>
<script src="https://cdn.jsdelivr.net/npm/@ibowankenobi/taskq/taskq.js"></script>
...
<script src="../isUserLogged.js" async></script>
<script src="home.js" async></script>
</head>
,并且顶部还有一个额外的常规
async
脚本。
现在只需进行一些更改即可获得所需的效果,本质上是用 iife(立即调用函数表达式)包装现有函数并添加一些 props。
taskq
我将
!function(){
function logMe(){
const token = localStorage.getItem("token");
const someObj = {value: null};
async function isUserSessionValid() {...}
async function validateUserSession() {
taskq.pause;
if(token != null) {
if(await isUserSessionValid()) {
someObj.value = token;
taskq.resume;
return;
}
}
...
}
validateUserSession();
taskq.export(someObj, "tokenObj");
}
logMe._taskqId = "first"
taskq.push(logMe)
}()
中的所有内容放入名为 isUserLogged
的函数中,并将其包装在 iife 中。我给它一个
logMe
首先并将其推入执行流程。我在验证函数中暂停/恢复了taskq。我还导出了一个您可以直接使用的变量。
本质上与
_taskqId
相同:
home.js
以上函数将等待!function(){
function home(tokenObj){
//contents of your home.js
...
}
home._taskqId = "home";
home._taskqWaitFor = ["first"]
}()
执行。我们之前导出的 first
也可以在
tokenObj
中使用,因此
home
是您用户的
tokenObj.value
。就是这样。
你也可以在
token
中使用taskq.load("./home.js")而不是isUserLogged.js
,你有几个选项
。请注意,该解决方案将在包含的 ie10 上运行,并且也可以轻松地与现代 es6 模块结合使用。您始终可以推出类似于 taskq 的自己的解决方案,它们都围绕在执行之前存储函数。
免责声明:我是taskq的开发者。