Socket.IO新客户端同步问题:如何让新客户端获取全量图片状态
解决Socket.IO客户端状态同步问题:新连接客户端获取历史图片
嘿,这个问题我之前做实时协作类应用时也碰到过!核心原因就是你的服务器没有保存已添加的图片历史记录,新客户端连接时根本拿不到之前的内容,只能接收连接之后新增的图片。老客户端因为之前已经收到过那些历史数据,所以界面有完整列表,新客户端就只能从自己连接的时刻开始“断片”了。
下面给你分步修改方案,保证所有客户端不管什么时候连进来,界面状态都完全一致:
第一步:修改服务器端代码
我们需要在服务器里加一个数组来存所有已发送的图片URL,新客户端一连接就主动把这个数组发给他;同时处理新图片的添加请求,更新数组后再广播给所有人。
const express = require('express'); const socketIO = require('socket.io'); const http = require('http'); // app set up const app = express(); const server = http.Server(app); let port = process.env.PORT || 3000; // static files app.use(express.static('app')); // socket setup & pass SERVER const io = new socketIO(server); // 新增:用这个数组存所有已添加的图片URL const imageHistory = []; io.on('connection', (socket) => { console.log('made connection!!!'); // 新增:新客户端刚连进来,立刻把历史图片列表发给他 socket.emit('imageHistory', imageHistory); // 把原来的'test'事件改成更语义化的'addImage' socket.on('addImage', function(data){ console.log('SERVER received image: ' + data.image); // 先把新图片加到历史数组里 imageHistory.push(data.image); // 广播给所有在线客户端(包括发请求的那个) io.sockets.emit('newImage', data); }); }); io.on('connect_error', function(){ console.log('fail'); }); server.listen(port, () => { console.log('server running....'); });
第二步:修改客户端代码
客户端这边要做的是:
- 连接成功后接收服务器发的历史图片,批量渲染到界面
- 单独监听“新增图片”的事件,只渲染单张新图
- 还要修正原代码里的一个小坑:你之前每次点击按钮都绑定一次
socket.on('test'),会导致同一个事件被多次监听,点一次按钮可能触发好几次渲染!
import $ from 'jquery'; import SaveInput from './SaveInput'; import io from 'socket.io-client'; // make connection const socket = io.connect('localhost:3000'); class Display extends SaveInput { constructor(){ super(); // 别忘了调用父类的构造函数哦 this.pGrid = $('.pic-grid-container'); this.display = $('#btn-display'); this.buttons(); this.initSocketListeners(); // 把Socket监听放在这里,只绑定一次 } buttons (){ // click buttons this.display.click(this.displayEls.bind(this)); } // 初始化Socket监听,只在构造函数里执行一次 initSocketListeners() { // 接收历史图片列表,批量渲染 socket.on('imageHistory', (history) => { history.forEach(imgUrl => { this.renderImage(imgUrl); }); }); // 接收新增的单张图片,渲染到界面 socket.on('newImage', (data) => { this.renderImage(data.image); }); } // 把渲染图片的逻辑封装成通用方法,避免重复代码 renderImage(imgUrl) { const $picContainer = $('<div class="picture-frame"></div>'); const $newImg = $('<img>').attr('src', imgUrl); $newImg.appendTo($picContainer); this.pGrid.append($picContainer); } // 点击按钮时,只发送新增图片的请求,渲染交给Socket监听处理 displayEls() { let img = './assets/images/baseball/team0.jpg'; socket.emit('addImage', { image: img }); } } export default Display;
改完之后的效果
不管客户端什么时候连接,一上来就会收到服务器发的所有历史图片,自动渲染到界面;之后再新增图片时,所有在线客户端(包括新连接的)都会实时收到并渲染,完全保证界面状态一致。
内容的提问来源于stack exchange,提问作者user2247061
相关产品推荐
相关产品推荐

