如何访问ExpressJS App Server静态方法并解决调用报错问题
问题原因
- 实例属性和静态属性混淆:你将
serverSocket挂载到了AppServer的实例对象属性上,但getServerSocket是静态方法,静态方法内的this指向AppServer类本身,类本身并没有挂载serverSocket属性,就算静态方法能正常调用也拿不到正确的值。 - 模块导出逻辑问题:你在模块内完成了
AppServer的实例化,但是导出的是类本身而非全局唯一的实例,如果存在模块循环引用的情况,还会导致引入的AppServer是不完整的空对象,直接触发getServerSocket is not a function报错。 - 隐式变量缺失:你原代码中没有显式声明
server和app变量,初始化时会额外触发变量未定义错误。
修复方案
推荐使用更符合场景的单例模式实现全局共享服务器实例,修改成本最低:
- 调整
server.js的代码逻辑:
const express = require('express'); const http = require('http'); const ServerSocket = require('./sockets/server_socket'); const app = express(); // 初始化http server实例,给socket.io用 const server = http.createServer(app); class AppServer { constructor() { this.initServerSocket(server); } initServerSocket(server) { this.serverSocket = new ServerSocket(server); } // 改为实例方法,直接拿当前实例的socket对象 getServerSocket() { return this.serverSocket; } start() { const port = process.env.PORT || 8000; server.listen(port, function () { console.log(`Server running on port ${port} in ${app.get("env")} mode`); }); } } // 全局仅实例化一次,所有文件共享这个实例 const appServer = new AppServer(); appServer.start(); // 导出实例而非类 module.exports = appServer;
- 调整其他文件的调用逻辑:
// 直接引入全局共享的实例 const appServer = require('../server'); function emitEvent(event){ appServer.getServerSocket().io.emit(event); }
如果坚持要使用静态方法实现,可以调整属性挂载逻辑,把socket实例挂到类本身的静态属性上:
const ServerSocket = require('./sockets/server_socket'); const app = express(); const server = http.createServer(app); class AppServer { // 声明静态属性存储socket实例 static serverSocket = null; constructor() { this.initServerSocket(server); } initServerSocket(server) { // 把实例挂到类的静态属性上,而非实例属性 AppServer.serverSocket = new ServerSocket(server); } static getServerSocket() { return AppServer.serverSocket; } start() { const port = process.env.PORT || 8000; server.listen(port, function () { console.log(`Server running on port ${port} in ${app.get("env")} mode`); }); } } let appServer = new AppServer(); appServer.start(); module.exports = AppServer;
注意事项
如果修改后仍出现getServerSocket is not a function报错,检查是否存在模块循环引用:比如server.js引入了其他业务文件,该业务文件又反过来引入server.js,这种情况会导致模块加载时拿到不完整的空对象,可以把引入逻辑放到函数内部做延迟加载解决。
内容的提问来源于stack exchange,提问作者ololo
相关产品推荐
相关产品推荐

