Express+Jade页面加载时偶现数据未定义错误的排查求助
Express.js + PostgreSQL 随机出现"Cannot read properties of undefined (reading 'data')"问题解决
问题根源
你遇到的随机错误本质是异步操作执行顺序混乱:
- 你发起了三个独立的数据库查询,它们并行执行,没有等待前两个查询完成就触发了第三个查询的回调(调用
res.render)。 - 当第三个查询先执行完毕时,
users_list和users_not_in_group_list还未被赋值,仍为undefined。此时模板里访问group_users.data(即undefined.data)就会抛出错误。 - 另外,模板里的
group_users.data是错误用法:users_list是查询返回的rows数组,判断长度应该用length而非data。
修复方案
1. 用Promise.all统一处理并行异步查询
将数据库查询封装为Promise,等待所有查询完成后再渲染页面:
//Create a group detail page router.get('/details', function (req, res, next) { if (req.session.loggedin) { const groupName = req.query.group; // 封装查询为Promise const getGroupUsers = () => { const userssql = 'select * from "TrustCalendar"."User" where $1 = any ("User"."Groups")'; return db.pool.query(userssql, [groupName]); }; const getRemainingUsers = () => { const users_not_in_group_sql = 'select * from "TrustCalendar"."User" where not $1 = any("User"."Groups")'; return db.pool.query(users_not_in_group_sql, [groupName]); }; const getGroup = () => { const sql = 'select * from "TrustCalendar"."Group" where lower("name") = lower($1)'; return db.pool.query(sql, [groupName]); }; // 等待所有查询完成后再渲染 Promise.all([getGroupUsers(), getRemainingUsers(), getGroup()]) .then(([usersResult, remainingResult, groupResult]) => { const users_list = usersResult.rows; const users_not_in_group_list = remainingResult.rows; const group = groupResult.rows; res.render('group-detail', { group, training_hours: group[0].training_hours, group_users: users_list, remaining_users: users_not_in_group_list }); }) .catch(error => { next(error); // 交给Express错误中间件处理,避免应用崩溃 }); } else { req.flash('error', 'Please log in!'); res.redirect('/'); } })
2. 修复Jade模板的错误逻辑
修改group_users.data为group_users.length,同时增加空值判断,避免变量未定义时出错:
extends layout block content h1 Group detail overview h2 #{group[0].name} p a(href="/groups/trainings") Trainings p Head of group p #{group[0].head_of_group} p Trainers of #{group[0].name} form(action="/groups/addtrainer?group=" + group[0].name, method="post") div add a user to #{group[0].name} if remaining_users && remaining_users.length <= 0 p All users are already in the group else if remaining_users select(name="user" multiple='multiple' data-placeholder="Choose user(s)" class="chosen-select" required) each user in remaining_users option(value=user.Name + ' ' + user.LastName) #{user.Name + ' ' + user.LastName } if !group_users || group_users.length <= 0 p No users in group else each user in group_users p=user.Name + ' ' + user.LastName a(href="/groups/removetrainer?group="+group[0].name + '&user_name=' + user.Name + '&user_lname=' + user.LastName) remove trainer
关键说明
- 异步操作必须确保所有依赖数据准备完成后再渲染,Promise.all是处理并行异步任务的标准方式。
- 模板中增加变量存在性判断(如
!group_users),可以避免因变量未定义导致的崩溃。 - 不要直接抛出错误,改用
next(error)交给Express错误处理中间件,提升应用稳定性。
内容的提问来源于stack exchange,提问作者Kasper Vanderhulst
相关产品推荐
相关产品推荐

