调用实例属性遇TypeError报错,及DatabaseController效率疑问求解
问题分析与解决方案
一、报错原因:this 上下文丢失
你遇到的 TypeError: Cannot read property 'sendError' of undefined 核心问题是回调函数里的 this 指向发生了偏移,不再指向 SocketHelper 的实例。
看这段 SocketHelper.js 里的代码:
SocketHelper.prototype.getUserById = function(id, callback){ DatabaseController.databaseQuery("SELECT * FROM users WHERE id = ?", id, function (error, user) { if(error || !user.length > 0) { return this.instance.sendError("Couldn't find a user with ID: " + id); } return callback(null, user[0]); }); };
当 databaseQuery 执行完毕调用这个匿名回调时,函数内部的 this 已经脱离了 SocketHelper 实例的上下文(普通函数作为回调时,this 默认指向全局对象或严格模式下的 undefined),所以 this.instance 自然就是 undefined,访问 sendError 就触发了报错。
修复方案(三种任选其一)
- 提前保存实例引用:
在getUserById开头把当前实例存到变量里,回调里用这个变量代替this:SocketHelper.prototype.getUserById = function(id, callback){ const self = this; // 保存当前SocketHelper实例 DatabaseController.databaseQuery("SELECT * FROM users WHERE id = ?", id, function (error, user) { if(error || !user.length > 0) { return self.instance.sendError("Couldn't find a user with ID: " + id); } return callback(null, user[0]); }); }; - 使用箭头函数继承上下文:
箭头函数不会绑定独立的this,会直接继承外层作用域的this:SocketHelper.prototype.getUserById = function(id, callback){ DatabaseController.databaseQuery("SELECT * FROM users WHERE id = ?", id, (error, user) => { if(error || !user.length > 0) { return this.instance.sendError("Couldn't find a user with ID: " + id); } return callback(null, user[0]); }); }; - 用
bind强制绑定上下文:
给回调函数手动绑定当前实例的this:SocketHelper.prototype.getUserById = function(id, callback){ DatabaseController.databaseQuery("SELECT * FROM users WHERE id = ?", id, function (error, user) { if(error || !user.length > 0) { return this.instance.sendError("Couldn't find a user with ID: " + id); } return callback(null, user[0]); }.bind(this)); // 绑定当前SocketHelper实例 };
二、DatabaseController 的效率分析与优化建议
当前你的 DatabaseController 是可用的,但存在可优化的空间:
每次执行 databaseQuery 都手动调用 pool.getConnection() 获取连接、执行后再 connection.release() 释放,虽然用了连接池,但这种手动管理方式冗余且没必要——mysql 连接池本身提供了 pool.query() 方法,它会自动处理连接的获取与释放,既减少重复代码,也避免了忘记释放连接导致的连接泄漏风险。
优化后的示例代码:
// 假设你已经完成了pool的初始化 module.exports = { // 如果没有单独使用createDatabaseConnection的场景,这个方法可以直接移除 createDatabaseConnection: function(callback) { pool.getConnection(function(error, connection) { if(error){ return callback(error); } return callback(null, connection); }); }, databaseQuery: function(query, parameters, callback) { if(parameters){ query = mysql.format(query, parameters); } // 直接使用pool.query,自动管理连接生命周期 pool.query(query, function(error, result) { if(error){ return callback(error); } return callback(null, result); }); } };
优化后不仅代码更简洁,连接池的复用逻辑也会更高效,因为 pool.query 内部会优化连接的分配与回收策略。
内容的提问来源于stack exchange,提问作者Richard Woodi
相关产品推荐
相关产品推荐

