Search code examples
javascriptnode.jsecmascript-6es6-promise

How can we use promise under readline.on function on (Node.js 8. Currently)


Not able to use await/async under readline.on function i don't know why it is not waiting untill results to return ? also used promise under await function but no use when i return promise also no use. Can any one who expert in node js,Es6 Please help me, This is my humble request to all developers. Can any one please help me to solve this issue and Thanks in advance.

var readline = require('readline');
fs = require('fs');
redis = require('redis');

var redisClient = redis.createClient();

var filePath = './sample-data/whoodle_index_file_0.psv';

async function getSampleData() {
    let rl = readline.createInterface({
        input: fs.createReadStream(filePath),
        crlfDelay: Infinity
    });

    rl.on('line', async (line) => {

        let obj = {};
        let data = line.split('|');
        obj['name'] = data[0];

        console.log('first line of execution process');

        let result = await getDataFromRedisUsingKey(obj['name']);
        console.log('result' + result);
        console.log('secound line of execution process');
        console.log('want to use this results in to some other functions');

        let obj2 = {};
        obj2['name'] = data[3];

        console.log('third line of execution process');

        let result2 = await getDataFromRedisUsingKey(obj2['name']);
        console.log('result' + result);
        console.log('fourth line of execution process');
        console.log('want to use this results in to some other functions');

    });

}

getSampleData();

async function getDataFromRedisUsingKey(name) {
    return new Promise(function (resolve, reject) {
        redisClient.get(name, function (err, result) {
            console.log("result----------------------" + result);
            if (err) {
                reject();
            } else {
                resolve(result);
            }
        });
    });
}

Showing result like this on console 

first line of execution process
first line of execution process
result----------------------null
result----------------------null
resultnull
secound line of execution process
want to use this results in to some other functions
third line of execution process
resultnull
secound line of execution process
want to use this results in to some other functions
third line of execution process
result----------------------null
result----------------------null
result2null
fourth line of execution process
want to use this results in to some other functions
result2null
fourth line of execution process
want to use this results in to some other functions

But im expecting like this

first line of execution process
result----------------------null
resultnull
secound line of execution process
want to use this results in to some other functions
third line of execution process
result----------------------null
result2null
fourth line of execution process
want to use this results in to some other functions
first line of execution process
result----------------------null
resultnull
secound line of execution process
want to use this results in to some other functions
third line of execution process
result----------------------null
result2null
fourth line of execution process
want to use this results in to some other functions

Solution

  • For what it's worth, here's a mock-up for the expected behavior, using an array of promises as a "waiting condition":

    // mock-up rl
    const EventEmitter = require('events');
    const rl = new EventEmitter();
    
    // mock-up the getDataFromRedis thing: this gives a Promise that is fulfilled after 1s
    function doSomething() {
      return new Promise((resolve, reject) => {
        setTimeout(resolve, 1000);
      });
    }
    
    // "waiting condition" variable
    const lockers = [];
    
    rl.on('line', () => {
      // wrap the code in a Promise that we add as a waiting condition
      lockers.push(new Promise(async (resolve, reject) => {
        // now we wait for all previously registered conditions to be OK before going on
        await Promise.all(lockers);
        // now we do the code with Redis
        console.log('x1');
        const r1 = await doSomething();
        console.log('x2');
        const r2 = await doSomething();
        // finally we resolve the current Promise to release lock on following processes
        resolve();
      }));
    });
    
    // start the process: mock-up rl's behavior: fire several events in a row
    for (let i = 0; i < 10; i++) {
        rl.emit('line');
    }
    

    However, this architecture is really weird: why do you need to "sequentialize" the process? I mean: even if everything goes parallel, you can still retrieve ordered data in the end, assuming you code the thing for it!

    To explain what happens under the hood:

    • rl fires "line"
    • JS summons the listener to that event, and as a good single-threaded event-based language, it executes the listener's code until it reaches the first await, then it checks if another piece of code requested processing
    • in the mean time, rl fired another (or some other) "line" event, so that's "another piece of code that requests processing", therefore JS executes it, until it reaches an await or the like
    • again, on await it'll go check its queue of events to process, and now you guess what happens if rl fires events faster than your inner code's first await: all of rl's events will be first in line for interpreter time, and all your inner code will have to wait before being ready to process their last bits of code

    However, when JS starts again processing your inner code (i.e. after Redis' async function resolved and after any previously registered event has been processed), it loads it with its scope, so you don't have to worry about mixing your data. The only worrying point is retrieving the order of that data: if needed, then you have to explicitly consider it, for instance using an array of promises (as the Promise objects in the array obviously stay in order, no matter the execution order of these Promises).