如何不使用Ajax/jQuery等待异步函数执行完成?JWT验证问题
问题
前端验证JWT时,登录获取token的代码如下:
.then((response) => { if(response.data.token) { localStorage.setItem('token', response.data.token); localStorage.setItem('user', response.data.user); console.log("Auth: ", auth);
随后调用validateToken函数验证token:
const validateToken = () => { Axios.get("https://xx.xxx.xx.xx:xxxx/checkAuth", { headers: {"access-token": localStorage.token} }).then((response) => { setAuth(response.data); }) };
该函数会从后端获取响应并存入response.data,但在登录逻辑中调用validateToken后,后续代码会在该函数执行完成前就运行:
const validateToken = () => { Axios.get("https://xx.xxx.xx.xx:xxxx/checkAuth", { headers: {"access-token": localStorage.token} }).then((response) => { localStorage.authState = response.data; }) }; const handleSubmit = async (e) => { e.preventDefault(); const login = () => { Axios.post("https://xx.xxx.xx.xx:xxxx/login", { email: email, password: pwd }).then((response) => { if(response.data.token) { localStorage.setItem('token', response.data.token); localStorage.setItem('user', response.data.user); validateToken(); // 此处调用后,后续代码直接执行 // 需要在validateToken执行完成后,再执行成功/失败逻辑 } else { if(response.data.message === "401") { setErrMsg('Missing Username or Password.'); } else if(response.data.message === "402") { setErrMsg("User doesn't exist."); } else { setErrMsg('No Server Response'); } } }) .catch(function (error) { if (error.response) { console.log("Error: ", error.response.data); } });
尝试将响应存入localStorage或变量,判断结果执行不同逻辑但无效,例如:
validateToken(); console.log(localStorage.AuthState); // 总是返回undefined
想知道如何不使用Ajax或jQuery,等待validateToken函数执行完成后再执行后续逻辑?
解决方案
核心问题是validateToken内部的Axios请求是异步操作,当前函数没有返回Promise,导致无法等待其执行完成。只需改造函数并利用Promise特性处理即可:
1. 让validateToken返回Promise
修改validateToken,使其返回Axios请求的Promise,同时修正localStorage的使用方式(localStorage仅支持存储字符串,对象需序列化):
const validateToken = () => { // 返回Axios请求的Promise,供后续等待 return Axios.get("https://xx.xxx.xx.xx:xxxx/checkAuth", { headers: {"access-token": localStorage.token} }).then((response) => { const authState = response.data; // 正确存储对象到localStorage localStorage.setItem('authState', JSON.stringify(authState)); return authState; // 将验证结果返回,供后续逻辑使用 }).catch(error => { // 捕获验证失败的错误,便于后续处理 console.error("Token验证失败:", error); throw error; // 抛出错误,让调用方可以捕获 }); };
2. 在登录逻辑中等待validateToken完成
根据代码风格,有两种实现方式:
方式一:使用async/await(代码更简洁清晰)
因为handleSubmit已经标记为async,可以直接在内部使用await等待异步操作完成:
const handleSubmit = async (e) => { e.preventDefault(); try { const response = await Axios.post("https://xx.xxx.xx.xx:xxxx/login", { email: email, password: pwd }); if(response.data.token) { localStorage.setItem('token', response.data.token); // 序列化user对象后存储 localStorage.setItem('user', JSON.stringify(response.data.user)); try { // 等待validateToken执行完成 const authState = await validateToken(); // 验证成功后的逻辑:比如跳转首页、更新页面状态等 console.log("Token验证成功:", authState); } catch (error) { // 验证失败后的逻辑:比如提示错误、清除token等 setErrMsg("Token验证失败,请重新登录"); localStorage.removeItem('token'); } } else { // 登录返回无token的处理逻辑 if(response.data.message === "401") { setErrMsg('缺少用户名或密码'); } else if(response.data.message === "402") { setErrMsg("用户不存在"); } else { setErrMsg('服务器无响应'); } } } catch (error) { if (error.response) { console.log("登录错误: ", error.response.data); setErrMsg("登录失败,请检查账号密码"); } } };
方式二:使用.then()链式调用
如果不想用async/await,可以在登录的.then()链中继续调用validateToken:
const handleSubmit = (e) => { e.preventDefault(); Axios.post("https://xx.xxx.xx.xx:xxxx/login", { email: email, password: pwd }).then((response) => { if(response.data.token) { localStorage.setItem('token', response.data.token); localStorage.setItem('user', JSON.stringify(response.data.user)); // 链式调用validateToken,将Promise传递下去 return validateToken(); } else { // 处理无token情况,返回rejected Promise进入catch if(response.data.message === "401") { setErrMsg('缺少用户名或密码'); } else if(response.data.message === "402") { setErrMsg("用户不存在"); } else { setErrMsg('服务器无响应'); } return Promise.reject(new Error("登录返回无token")); } }).then(authState => { // Token验证成功后的逻辑 console.log("Token验证成功:", authState); }).catch(error => { // 捕获登录或验证过程中的所有错误 if (error.response) { console.log("错误: ", error.response.data); } else { console.error(error.message); } setErrMsg("操作失败,请重试"); }); };
3. 原代码无效的原因
- Axios请求是异步操作,调用
validateToken()后代码会直接往下执行,不会等待请求完成,所以console.log(localStorage.AuthState)会先执行,此时请求还未返回,自然是undefined。 - 直接赋值
localStorage.authState不符合localStorage的API规范,必须使用setItem和getItem方法,且存储对象时需要用JSON.stringify序列化,读取时用JSON.parse解析。
内容的提问来源于stack exchange,提问作者npatrik30
相关产品推荐
相关产品推荐

