efong5
efong5

Reputation: 526

Node readline input overlap

When I have multiple readline objects, even when they are opened and closed within the same closure, I end up seeing strange behavior.

In the tick tac toe game I am practicing making, I run into the issue where readline.interface.question terminates without receiving input, and without entering the callback.

In the case below, where I have tried to isolate the issue, prompts occasionally duplicate my inputs (ex. typing "1" results in "11")

How should readline.interface.question be used synchronously?

const EventEmitter = require('events');
const readline = require('readline');



function Emitter() {
    EventEmitter.call(this);
    this.val = 1;
    this.ping = () => {
        console.log(this.val);
        readAndPrint(() => {
            this.emit('emit');
        });
    }

    this.setEmitter = (emitter) => {
        emitter.on('emit', this.ping);
    }

    const readAndPrint = (callback) => {
        const reader = readline.createInterface({
            input: process.stdin,
            output: process.stdout,
        });

        reader.question('Enter a string: ', (answer) => {
            reader.close();
            console.log(answer);
            callback();
        })
    }
}
Emitter.prototype.__proto__ = EventEmitter.prototype;




let one = new Emitter();
let two = new Emitter();
let three = new Emitter();
one.setEmitter(three);
two.setEmitter(one);
three.setEmitter(one);

one.ping();

Upvotes: 2

Views: 240

Answers (1)

CXNAJ
CXNAJ

Reputation: 43

My guess is that because all your this.pings are triggered by the same "emit" when you setEmitter. So after your one.ping() the callback trigger an "emit" and this.ping for two,three go off after one is closed.

You can try giving each emitter an id so they dont all trigger each emitter's this.ping

const EventEmitter = require("events");
const readline = require("readline");

function Emitter(id) {
    EventEmitter.call(this);
    this.val = 1;
    this.id = id;
    this.ping = () => {
        console.log(this.val);
        readAndPrint(() => {
            this.emit("emit" + this.id);
        });
    };

    this.setEmitter = emitter => {
        emitter.on("emit" + this.id, this.ping);
    };

    const readAndPrint = function(callback) {
        const reader = readline.createInterface({
            input: process.stdin,
            output: process.stdout
        });

        reader.question("Enter a string: ", answer => {
            reader.close();
            console.log(answer);
            callback();
        });
    };
}
Emitter.prototype.__proto__ = EventEmitter.prototype;

let one = new Emitter(1);
let two = new Emitter(2);
let three = new Emitter(3);
one.setEmitter(three);
two.setEmitter(one);
three.setEmitter(one);

one.ping();

Here is a snippet to give you a better understanding of what's happening. Basically your code calls one.ping(), it closes then two.ping and three.ping go off from your callback "emit"

const EventEmitter = require("events");
const readline = require("readline");

function Emitter(id) {
    EventEmitter.call(this);
    this.val = 1;
    this.id = id;
    this.ping = () => {
        readAndPrint(() => {
            this.emit("emit");
        });
    };

    this.setEmitter = emitter => {
        emitter.on("emit", this.ping);
    };

    const readAndPrint = callback => {
        console.log("my id is:", this.id);
        const reader = readline.createInterface({
            input: process.stdin,
            output: process.stdout
        });

        reader.question("Enter a string: ", answer => {
            reader.close();
            console.log(answer);
            callback();
        });
    };
}
Emitter.prototype.__proto__ = EventEmitter.prototype;

let one = new Emitter(1);
let two = new Emitter(2);
let three = new Emitter(3);
one.setEmitter(three);
two.setEmitter(one);
three.setEmitter(one);

one.ping();

To do it synchronously, you can use callbacks like so:

const EventEmitter = require("events");
const readline = require("readline");

function Emitter(id) {
    EventEmitter.call(this);
    this.val = 1;
    this.id = id;
    this.ping = cb => {
        readAndPrint(() => {
            this.emit("emit" + this.id);
            if (cb) {
                cb();
            }
        });
    };

    this.setEmitter = emitter => {
        emitter.on("emit" + this.id, this.ping);
    };
    this.removeListener = emitter => {
        emitter.removeListener();
    };

    const readAndPrint = callback => {
        const reader = readline.createInterface({
            input: process.stdin,
            output: process.stdout
        });

        reader.question("Enter a string: ", answer => {
            console.log("my id is: ", this.id);
            reader.close();
            console.log(answer);
            callback();
        });
    };
}
Emitter.prototype.__proto__ = EventEmitter.prototype;

let one = new Emitter(1);
let two = new Emitter(2);
let three = new Emitter(3);
one.setEmitter(three);
two.setEmitter(one);
three.setEmitter(one);

one.ping(() => two.ping());

Upvotes: 1

Related Questions