异步函数执行顺序异常:对象未填充完成后续函数已执行
异步函数执行顺序问题的解决方案
问题根源
queryPermissionsId()内部的数据库查询是异步回调操作,但这个函数没有提供任何等待异步操作完成的机制。当你在main.js里调用它后,JavaScript引擎会立即继续执行后续的console.log、profileData.testAccount()等同步代码,此时数据库查询还未返回结果,pfData的权限属性自然还是undefined。
JavaScript的单线程特性决定了:异步任务(比如数据库请求)会被放入事件队列,只有当前同步代码全部执行完毕后,才会处理队列里的异步回调。这就是你看到控制台输出顺序不符合预期的原因。
解决方案:将异步回调改造为Promise
要让后续逻辑等待queryPermissionsId()完成,需要把它改造成返回Promise的函数,然后通过async/await或.then()来控制执行顺序。
方案1:使用async/await(推荐,代码更简洁)
1. 改造profileData.js的queryPermissionsId
先把回调式的connection.query转成Promise版本(Node环境下用util.promisify):
// 引入util模块(如果还没引入) const util = require('util'); // 把connection.query转成Promise版本 const queryAsync = util.promisify(connection.query).bind(connection); async function queryPermissionsId() { try { // 第一个查询:获取accountId const accountQuery = "SELECT id FROM `accounts` WHERE email = ?"; console.log(accountQuery, [pfData.email]); const accountResult = await queryAsync(accountQuery, [pfData.email]); console.log(accountResult); const accountId = accountResult[0].id; // 第二个查询:获取权限数据 const permQuery = "SELECT * FROM `permissions` WHERE accountId = ?"; const permissionsResult = await queryAsync(permQuery, [accountId]); console.log(permissionsResult[0]); // 填充pfData的权限属性 const permData = permissionsResult[0]; pfData.accountId = permData.accountId; pfData.can_see_inventory = permData.can_see_inventory; pfData.can_see_employees = permData.can_see_employees; pfData.can_see_past_orders = permData.can_see_past_orders; pfData.can_see_open_orders = permData.can_see_open_orders; pfData.can_create_order = permData.can_create_order; pfData.can_change_privialages = permData.can_change_privialages; pfData.can_create_inventory_items = permData.can_create_inventory_items; pfData.can_create_inventory_categories = permData.can_create_inventory_categories; pfData.is_admin = permData.is_admin; console.log(pfData); } catch (err) { console.error('查询权限失败:', err); } }
2. 修改main.js的调用逻辑
用async/await等待queryPermissionsId完成:
profileData.getProfile() .then(async () => { $(document).ready(async function() { // 等待权限查询完成 await profileData.queryPermissionsId(); // 后续逻辑现在会在pfData填充完成后执行 loadNav(); console.log(profileData.pfData); console.log(profileData.pfData.is_admin); profileData.testAccount(); // 创建页面元素 }); })
方案2:手动封装Promise(不依赖async/await)
如果环境不支持async/await,可以手动把queryPermissionsId封装成Promise:
function queryPermissionsId() { return new Promise((resolve, reject) => { // 第一个查询 const accountQuery = "SELECT id FROM `accounts` WHERE email = ?"; console.log(accountQuery, [pfData.email]); connection.query(accountQuery, [pfData.email], function(err, accountResult) { if (err) { console.error(err); return reject(err); } console.log(accountResult); const accountId = accountResult[0].id; // 第二个查询 const permQuery = "SELECT * FROM `permissions` WHERE accountId = ?"; connection.query(permQuery, [accountId], function(err, permissionsResult) { if (err) { console.error(err); return reject(err); } console.log(permissionsResult[0]); // 填充pfData const permData = permissionsResult[0]; pfData.accountId = permData.accountId; pfData.can_see_inventory = permData.can_see_inventory; pfData.can_see_employees = permData.can_see_employees; pfData.can_see_past_orders = permData.can_see_past_orders; pfData.can_see_open_orders = permData.can_see_open_orders; pfData.can_create_order = permData.can_create_order; pfData.can_change_privialages = permData.can_change_privialages; pfData.can_create_inventory_items = permData.can_create_inventory_items; pfData.can_create_inventory_categories = permData.can_create_inventory_categories; pfData.is_admin = permData.is_admin; console.log(pfData); resolve(); }); }); }); }
然后main.js里用.then()等待:
profileData.getProfile() .then(() => { $(document).ready(function() { profileData.queryPermissionsId() .then(() => { loadNav(); console.log(profileData.pfData); console.log(profileData.pfData.is_admin); profileData.testAccount(); // 创建页面元素 }) .catch(err => console.error(err)); }); })
额外提醒:避免SQL注入
原来的代码直接拼接SQL字符串,存在严重的SQL注入风险。上面的改造中已经改用参数化查询(用?作为占位符,把参数放在数组里传递),这是操作数据库的最佳实践,务必保留这个写法。
内容的提问来源于stack exchange,提问作者Wadert3
相关产品推荐
相关产品推荐

