解决Promise调用报错Cannot read property 'then' of undefined
问题背景
正在开发练习项目LightBnB,属于平价版类Airbnb民宿预订网站。
预订功能预期逻辑:用户在房源列表点击「Make Reservation(发起预订)」按钮,选择入住/退房日期提交后,前端会向服务端发送HTTP请求完成预订创建。当前功能运行时触发报错,无法正常完成预订流程。
报错信息
TypeError: Cannot read property 'then' of undefined at /vagrant/LightBnB/LightBnB_WEB_APP/server/apiRoutes.js:44:7
报错触发位置对应路由中链式调用.then()处理预订返回结果的代码段:
.then((reservation) => { res.send(reservation);
关联代码
预订接口路由逻辑
router.post('/reservations', (req, res) => { const userId = req.session.userId; database .addReservation({ ...req.body, guest_id: userId }) .then((reservation) => { res.send(reservation); }) .catch((e) => { console.error(e); res.send(e); }); });
数据库操作方法addReservation实现
方法注释明确约定该方法需要返回Promise类型的预订结果:
/** * Add a reservation to the database * @param {{}} reservation An object containing all of the reservation details. * @return {Promise<{}>} A promise to the reservation. */ const addReservation = function (reservation) { const queryString = ` INSERT INTO reservations( start_date, end_date, property_id, guest_id ) VALUES ($1, $2, $3, $4) RETURNING * `; const values = [ reservation.start_date, reservation.end_date, reservation.property_id, reservation.guest_id, ]; pool .query(queryString, values) .then((res) => { res.rows; }) .catch((e) => console.log(e.message)); }; exports.addReservation = addReservation;
问题根因
报错的核心原因是addReservation方法没有返回任何值,默认返回undefined,路由代码对undefined调用.then()自然触发类型错误。具体存在两个细节问题:
- 方法内执行
pool.query()生成的Promise链没有加return关键字,整个方法没有对外返回Promise实例,完全不符合方法注释约定的返回Promise的要求 - 就算补了外层return,当前
pool.query().then()的回调里只写了res.rows,没有return这个查询结果,后续链式调用拿不到实际预订数据;且方法内部的catch仅打印错误日志、不向外抛出,会导致路由层的catch无法捕获数据库异常,错误会被静默吞掉。
修复方案
修改addReservation方法,补全return逻辑,正确返回Promise链和查询结果,同时把错误透传给上层路由统一处理:
const addReservation = function (reservation) { const queryString = ` INSERT INTO reservations( start_date, end_date, property_id, guest_id ) VALUES ($1, $2, $3, $4) RETURNING * `; const values = [ reservation.start_date, reservation.end_date, reservation.property_id, reservation.guest_id, ]; // 返回整个Promise链 return pool .query(queryString, values) .then((res) => { // 返回单条插入生成的预订记录,供上层逻辑获取 return res.rows[0]; }) .catch((e) => { console.log(e.message); // 抛出错误,交由路由层统一处理 throw e; }); }; exports.addReservation = addReservation;
修复后接口就能正常拿到Promise实例,链式调用.then()获取预订结果返回给前端,数据库操作异常也能正常被路由层捕获处理。
内容的提问来源于stack exchange,提问作者jhoangqm
相关产品推荐
相关产品推荐

