I was following the code snippet here https://github.com/socketio/socket.io-redis#redisadapterclientsroomsarray-fnfunction
io.in('room3').clients((err, clients) => {
console.log(clients); // an array containing socket ids in 'room3'
});
to get the clients in a particular room.
Is there a simple/idiomatic way I can make this snippet synchronous? I want to loop over an array of rooms and synchronously get the count of users clients.length in each room (ie don't iterate over the loop until the user count of the current room has been retrieved.)
You can make use of Promises and async await within a for loop
async function getClients() {
for(let room in rooms) {
try{
const promise = new Promise((res, rej) => {
io.in(room).clients((err, clients) => {
if(err) {
rej(err);
} else {
res(clients); // an array containing socket ids in room
}
});
})
const clients = await promise;
console.log(clients);
}catch(err) {
console.log(err)
}
};
}
Using the above manner will help you iterate over each room and get the clients sequentially one by one.
Although you can't force them to run synchronously
Wrapping a callback in a Promise gives you more control over the flow of the program.
// The purpose of this is just to convert a callback to a Promise:
// clientsInRoom('room1') is a promise that resolves to `clients` for that room.
const clientsInRoom = room => new Promise((resolve, reject) => {
io.in(room).clients((err, clients) =>
err ? reject(err) : resolve(clients)
)
})
If you are inside of an async function, you can use await, which will make asynchronous code feel more like synchronous code. (although "top-level await" is supported within modules in modern browsers)
async function main() {
const rooms = ['room1', 'room2', 'room3']
// If either one of the promises reject, the statement will reject
// Alternatively, you can use Promise.allSettled()
const allClients = await Promise.all(rooms.map(clientsInRoom))
// You can use map to turn this into an array of the lengths:
const lengths = allClients.map(clients => clients.length)
// Alternatively, if you want the feel of a synchronous loop:
for (const clients of allClients) {
console.log(clients.length)
}
}
Using for-await is also an option, if you want to start iterating before all promises have resolved:
async function main() {
const rooms = ['room1', 'room2', 'room3']
for await (const clients of rooms.map(clientsInRoom)) {
console.log(clients.length)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With