javascriptnode.jseventsudpdatagram

How can I wait for socket events in Javascript?


I am trying to use datagram sockets to make a simple game in Javascript, but I can't figure out how to wait for events like bind or message to happen. Can I use promisify for that?

This is my current code:

import { createSocket } from 'dgram';
import * as readline from 'node:readline/promises';
import { stdin as input, stdout as output } from 'node:process';

const client = createSocket('udp4');

const rl = readline.createInterface({ input, output });

client.on('connect', () => { console.log(`connected: ${client.remoteAddress().address}:${client.remoteAddress().port}`); });
client.on('close', () => { console.log('closed'); });

client.on('listening', () => {
    const addr = client.address();
    console.log(`client listening on ${addr.address}:${addr.port}`);
});

client.bind();

const address = await rl.question('Enter address: ');

And the terminal output:

āžœ node client.mjs
Enter address: client listening on 0.0.0.0:50432

Is question() being called before bind() is done or is it the event that is being triggered after question()? Either way, how can I ask for the address that I am going to message after bind() is done and the client address in shown?


Solution

  • You can wrap the asynchronous UDP initialization in a function that returns a promise so the caller can know when it's done:

    function initUDP() {
    
        return new Promise((resolve, reject) => {
            const client = createSocket('udp4');
    
            client.on('connect', () => { console.log(`connected: ${client.remoteAddress().address}:${client.remoteAddress().port}`); });
            client.on('close', () => { console.log('closed'); });
    
            client.on('listening', () => {
                const addr = client.address();
                console.log(`client listening on ${addr.address}:${addr.port}`);
                resolve(client);
            });
    
            client.bind();
            client.on('error', reject);
        });
    }
    
    initUDP().then(async client => {
        const rl = readline.createInterface({ input, output });
        const address = await rl.question('Enter address: ');
    
    }).catch(err => {
        console.log(err);
    });
    

    Note: The listening event does the same thing as the callback you can pass to .bind() so you just need to do one or the other.