NodeJS回调函数内调用handleDisconnect报错:TypeError问题排查
Node.js MySQL 连接丢失时调用对象方法报错:TypeError: this.handleDisconnect is not a function
我尝试实现MySQL连接断开重连的逻辑,但在回调函数里调用对象方法时遇到了问题。
我的index.js文件代码如下:
const db = require('./models/db.js'); db.connectDb();
db.js文件代码如下:
const mysql = require('mysql'); const database = { //连接数据库 connectDb : function () { // 创建连接 this.db = mysql.createConnection({ host: 'localhost', user: 'root', password: '', database: 'example' }); this.db.connect(function(err){ if(err){ console.log("连接数据库时发生错误。"); throw err; } console.log("MySQL Connected..."); }); this.db.on('error', function (err) { var currentdate = new Date(); console.log("发生错误 @ ", currentdate," 错误信息:", err); if(err.code === 'PROTOCOL_CONNECTION_LOST') { this.handleDisconnect(); } else { throw err; } }); }, handleDisconnect: function () { this.connectDb(); } } module.exports = database;
服务器启动后MySQL连接成功创建,为测试连接丢失处理逻辑,我重启了MySQL服务,此时this.db.on('error', function (err)被触发,终端输出连接丢失错误信息,但随后出现如下错误:
/home/folder/models/db.js:27 this.handleDisconnect(); ^ TypeError: this.handleDisconnect is not a function at Connection.<anonymous> (/home/folder/models/db.js:27:22) at Connection.emit (node:events:526:28) at Connection._handleProtocolError (/home/folder/node_modules/mysql/lib/Connection.js:423:8) at Protocol.emit (node:events:526:28) at Protocol._delegateError (/home/folder/node_modules/mysql/lib/protocol/Protocol.js:398:10) at Protocol.end (/home/folder/node_modules/mysql/lib/protocol/Protocol.js:116:8) at Socket.<anonymous> (/home/folder/node_modules/mysql/lib/Connection.js:94:28) at Socket.<anonymous> (/home/folder/node_modules/mysql/lib/Connection.js:526:10) at Socket.emit (node:events:538:35) at endReadableNT (node:internal/streams/readable:1345:12) [nodemon] app crashed - waiting for file changes before starting...
我的问题:
该错误是否与在回调函数内调用外部函数有关?能否在对象方法内的回调函数中调用对象的其他方法?或是其他原因导致的问题?
问题原因
这个错误完全是回调函数内的this指向问题。在传统的function()回调里,this的指向会被绑定到触发事件的对象(这里是MySQL的Connection实例),而不是你的database对象,所以自然找不到handleDisconnect方法。
解决方法
有三种常用的方式解决这个问题:
1. 使用箭头函数(推荐)
箭头函数不会绑定自己的this,它会继承外层作用域的this,也就是connectDb方法里的database对象:
this.db.on('error', (err) => { var currentdate = new Date(); console.log("发生错误 @ ", currentdate," 错误信息:", err); if(err.code === 'PROTOCOL_CONNECTION_LOST') { this.handleDisconnect(); // 这里的this指向database对象 } else { throw err; } });
2. 提前保存this到变量
在回调函数外把this赋值给一个变量(比如self/that),然后在回调里用这个变量访问对象方法:
connectDb : function () { const self = this; // 保存当前this指向的database对象 // ...其他代码 this.db.on('error', function (err) { var currentdate = new Date(); console.log("发生错误 @ ", currentdate," 错误信息:", err); if(err.code === 'PROTOCOL_CONNECTION_LOST') { self.handleDisconnect(); // 使用self代替this } else { throw err; } }); },
3. 使用bind()绑定this
通过bind()方法手动把回调函数的this绑定到database对象:
this.db.on('error', function (err) { var currentdate = new Date(); console.log("发生错误 @ ", currentdate," 错误信息:", err); if(err.code === 'PROTOCOL_CONNECTION_LOST') { this.handleDisconnect(); } else { throw err; } }.bind(this)); // 绑定当前this到回调函数
补充说明
当然可以在对象方法的回调里调用对象的其他方法,核心就是要保证回调里的this指向正确的对象。另外,你的重连逻辑还有个小问题:每次调用connectDb都会创建新的连接实例,记得旧连接如果还有残留要销毁,但mysql库在连接断开后会自动清理,所以目前的写法暂时没问题。
内容的提问来源于stack exchange,提问作者dot-wood
相关产品推荐
相关产品推荐

