javascriptnode.jsreadlineasync-iterator

JavaScript async sleep function somehow leads to silent exiting of program


I copied an async sleep function from here https://stackoverflow.com/a/39914235/7492244 Then I used it basically in this program. https://nodejs.org/api/readline.html#example-read-file-stream-line-by-line

So my own index.js looks like:

const fs = require('fs');
const readline = require("readline");

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function main() {
    const fileStream = fs.createReadStream('input.txt');
    let lineReader = readline.createInterface({
        input: fileStream,
        crlfDelay: Infinity,
    });
    console.log("Enter sleep");
    await sleep(1000);
    console.log("Exit sleep");

    for await (const line of lineReader) {
        console.log("line: " + line);
    }
    console.log("DONE");
}

main();

I get this mind boggling behaviour that it somehow prints Enter sleep and Exit sleep but not DONE. However it does terminate, and without printing any errors. I found out after hours of debugging that it works if I remove the call to sleep. What is wrong with this sleep function?

Edit: Note: I am specifically just trying to understand why the call to sleep breaks (afaics) the flow of the program. The use case or end goal is not important.


Solution

  • Ok, this one was strange.

    It seems like if you don't pause a stream while you do the timeout the process will terminate. No errors either, even try/catch and try/finally will fail..

    But if you pause & resume, this seems to fix the issue..

    eg..

    const fs = require('fs');
    const readline = require("readline");
    
    function sleep(ms) {
      return new Promise((resolve) => setTimeout(resolve, ms));
    }
    
    async function main() {
        const fileStream = fs.createReadStream('input.txt');
        let lineReader = readline.createInterface({
            input: fileStream,
            crlfDelay: Infinity,
        });
        console.log("Enter sleep");
        lineReader.pause();
        await sleep(1000);
        lineReader.resume();
        console.log("Exit sleep");
    
        for await (const line of lineReader) {
            console.log("line: " + line);
        }
        console.log("DONE");
    }
    
    main();
    

    ps, if you use sleep in the for await you don't need to pause.. So it appears if you don't start reading a stream straight away without pausing, that's when the issue occurs.

    Of course the other option is just call the sleep before the readline.createInterface, and the pause won't be required.