JavaScript async sleep function somehow leads to silent exiting of program

6.4k Views Asked by At

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.

2

There are 2 best solutions below

2
On BEST ANSWER

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.

4
On

This seem a bit strange that use of reading a stream;

since you can add event like this

const lines = []:
lineReader.on('line', line => lines.push(line))

and delete your for loop, in the end you can have only that

const fs = require('fs');                                                                                                                                                                                  
const readline = require("readline");                                                                                                                                                                      
                                                                                                                                                                                                           
function sleep(ms) {                                                                                                                                                                                       
  return new Promise((resolve) => setTimeout(resolve, ms));                                                                                                                                                
}                                                                                                                                                                                                          
                                                                                                                                                                                                           
async function main() {                                                                                                                                                                                    
    const lines = [];                                                                                                                                                                                      
    const fileStream = fs.createReadStream('text.txt');                                                                                                                                                    
    let lineReader = readline.createInterface({                                                                                                                                                            
        input: fileStream,                                                                                                                                                                                 
        crlfDelay: Infinity,                                                                                                                                                                               
    });                                                                                                                                                                                                    
    lineReader.on('line', line => lines.push(line))                                                                                                                                                        
    console.log("Enter sleep");                                                                                                                                                                            
    await sleep(1000);                                                                                                                                                                                     
    console.log("Exit sleep");                                                                                                                                                                             
    console.log(lines);                                                                                                                                                                                    
    console.log("DONE");                                                                                                                                                                                   
}                                                                                                                                                                                                          
                                                                                                                                                                                                           
main();

By the way it dosn't work your way since you have a timeout and the strezam close.

Just console.log the lineReader and you will see the status closed at true and multiple data like the timout it handle and everything :P