背景
在开发3D骰子联机小程序时,多人游戏功能需要实时同步房间的操作状态(如房主开盅动作)。初期采用小程序云开发数据库的watch
监听机制实现状态同步,虽能完成基础功能,但存在致命体验短板------云函数响应延迟高达1-2秒,与骰子游戏强实时的特性产生明显冲突。

于是为追求更丝滑的实时交互的用户体验,决定选择通过 WebSocket
重构通信层,下文将详解一下通过 nest
实现与小程序实时通信的方案。
实现
首先我们通过 nest
的脚手架来初始化一下项目
arduino
nest new websocket-demo
运行一下项目,启动成功

接着我们安装对应的所需的websocket的依赖
css
npm i --save @nestjs/websockets @nestjs/platform-ws ws
最开始用的 socket.io
依赖实现,结果后面发现小程序不支持 socket.io
,需要下载一些兼容库来结合使用,于是就换了方案。
接下来我们需要为应用注入 WebSocket 适配器,在main.ts中配置一下 主要作用
- 将传统的 HTTP 服务扩展为 同时支持 HTTP + WebSocket 双协议
- 通过适配器模式,让
WebSocket
的底层实现(如ws
或socket.io
库)与框架的路由、中间件等系统无缝对接。
js
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { WsAdapter } from '@nestjs/platform-ws';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useWebSocketAdapter(new WsAdapter(app));
await app.listen(3000);
}
bootstrap();
接下来需要配置一下 WebSocket
网关
js
import { SubscribeMessage, WebSocketGateway, WebSocketServer, OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect } from '@nestjs/websockets';
import { Server, WebSocket } from 'ws';
@WebSocketGateway(3001) // 指定ws端口号,不配置则默认与http服务相同端口
export class WsGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
@WebSocketServer()
server: Server;
// 初始化后执行
afterInit(server: Server) {
console.log('WebSocket server initialized');
}
// 处理新连接
handleConnection(client: WebSocket, ...args: any[]) {
console.log('Client connected:');
}
// 处理断开连接
handleDisconnect(client: WebSocket) {
console.log(`Client disconnected: ${client}`);
}
// 消息处理示例
@SubscribeMessage('message') // 这里的message对应的是前端发送ws请求的里的event值
handleMessage(client: WebSocket, payload: any): string {
console.log('handleMessage message:', payload);
client.send(JSON.stringify({ event: 'message', data: `我收到了你发的消息${payload}` })); // 回发消息
return 'OK';
}
}
还需要在 app.module.ts
中引入 socket
网关
js
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { WsGateway } from './ws.gateway';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService, WsGateway], // 这里
})
export class AppModule {}
我们重新跑一下后端服务
然后在小程序中的app.vue
中的 onLaunch
写连接本地 WebSocket
服务的代码
js
const conSocket = wx.connectSocket({
url: 'ws://localhost:3001',
success: () => console.log('Connecting...'),
})
// 监听事件
conSocket.onOpen(() => {
console.log('Connected!');
});
conSocket.onMessage((res: any) => {
const { data } = res
console.log('onMessage-msg', data);
});
conSocket.onError((err) => {
console.error('Error:', err);
});
conSocket.onClose(() => {
console.log('Connection closed');
});
小程序项目运行起来

发现连接成功了!!!
接下来我来试一下双向通信,在连接打开的时候,我们给服务端发送点内容
js
conSocket.onOpen(() => {
console.log('Connected!');
conSocket.send({
data: JSON.stringify({
event: 'message',
data: {
msg: 'Hello, server!'
}
}),
success: () => console.log('Message sent')
})
});

可以看到服务器与小程序之间的双向通信没问题,并且响应很快,非常符合我们的联机功能。
✨ 总结
-
旧方案:云数据库watch监听
- 延迟1-2秒,体验割裂
- 被动轮询,资源消耗大
-
新方案:NestJS+WebSocket
- 延迟<100ms,毫秒级响应
- 主动推送,节省资源
对于前端来说,用户体验极其重要,我自己在开发过程中,都会让自己从用户的角度,来体验流程,这也有助于自己去思考,去进行一些性能优化。