猿问

设置 Socket.io 房间变量

我想在套接字空间变量中存储一些信息,但出现以下错误:UnhandledPromiseRejectionWarning: TypeError: Cannot set property 'host' of undefined


这是我的代码:


io.on('connection', (socket, next) => {

    socket.on('create game', async () => {

        console.log('Creating game...');

        socket.username = await generateUsername();


        socket.roomId = generateId();


        socket.join(socket.roomId);


        io.sockets.adapter.rooms[socket.roomId].host = socket.username;

        io.sockets.adapter.rooms[socket.roomId].isOpen = true;

        io.sockets.adapter.rooms[socket.roomId].players = [socket.username];


        console.log('Game created! ID: ', socket.roomId);

    });

}

如果我尝试记录socket.roomId它会返回类似rBAhx0. 当我登录时io.sockets.adapter.rooms,我得到以下信息:


Map {

  'PX_o3Di9sp_xsD6oAAAB' => Set { 'PX_o3Di9sp_xsD6oAAAB' },

  'rBAhx0' => Set { 'PX_o3Di9sp_xsD6oAAAB' }

}

但是,当我尝试记录 时io.sockets.adapter.rooms[socket.roomId],它返回undefined。我怎样才能解决这个问题?


长风秋雁
浏览 188回答 3
3回答

HUWWW

Socket.io 在最新版本中进行了一些重大更改,无法像以前一样访问房间。它将很多对象和数组更改为映射和集合,您可以在您发布的日志中看到它。Set对象是值的集合。您可以按插入顺序迭代集合的元素。Set中的一个值只能出现一次;它在套装系列中是独一无二的。该Map对象保存键值对并记住键的原始插入顺序。任何值(对象和原始值)都可以用作键或值。访问映射的属性与访问普通对象的属性的方式不同。例子:const myMap = new Map();myMap.set("foo", "bar");console.log(myMap["foo"]) // undefinedconsole.log(myMap.get("foo")) // bar同样适用于集合,但是在您的情况下,特别查询此集合可能是错误的方法,因为此集合仅包含 id 的集合,而不是实际的房间对象。即使您要从 Set 中获取值,您也无法访问它的属性(主机、isOpen 和玩家),因为它只是一个字符串。恐怕 3.0 版本使得直接访问所有房间列表变得不可能了。然而,适配器现在有一个属性socketRooms,可以用来代替它。为了更容易地访问套接字的房间,您应该像这样访问它们:io.sockets.adapter.socketRooms(socketId);然而,这仍然只会返回一个字符串列表。此问题最简单的解决方案是在连接范围之外创建一个外部变量。const rooms = {};io.on('connection', (socket, next) => {    socket.on('create game', async () => {        console.log('Creating game...');        socket.username = await generateUsername();        socket.roomId = generateId();        socket.join(socket.roomId);        if (!rooms[socket.roomId]) rooms[socket.roomId] = {};        rooms[socket.roomId].host = socket.username;        rooms[socket.roomId].isOpen = true;        rooms[socket.roomId].players = [socket.username];        console.log('Game created! ID: ', socket.roomId);    });}

慕田峪9158850

在从 Socket.io 更改Array为Map. 一个简单的解决方案是改变:    io.sockets.adapter.rooms[socket.roomId].host = socket.username;到:    io.sockets.adapter.get(socket.roomId).host = socket.username;

牛魔王的故事

正如您在自己的日志中看到的,io.sockets.adapter.rooms是一个Map对象(在socket.io的更高版本中),而不是一个普通对象。这意味着房间是通过 访问的.get(),而不是通过简单的索引(例如您正在使用的索引)访问:io.sockets.adapter.rooms[socket.roomId].host = socket.username;这根本行不通,因为socket.roomId地图上没有普通属性。如果你想获取房间对象,你必须这样做:let roomObj = io.sockets.adapter.rooms.get(socket.roomId); roomObj.host = socket.username;在我看来,我不会直接弄乱房间里的物体。我们已经知道 socket.io 之前已经改变了他们的设计,将任何试图使用它们的代码渲染为损坏的并且需要重新设计。相反,我可能只是创建自己的数据结构,在其中存储自己的数据,然后我就不会依赖于 socket.io 如何改变其设计的突发奇想。直接访问房间对象不是socket.io 的承诺设计或承诺的API。他们可以随时改变它的工作方式,而且最近确实已经改变了它。
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答