Home > Mobile >  JavaScript async sleep function somehow leads to silent exiting of program
JavaScript async sleep function somehow leads to silent exiting of program

Time:03-24

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.

CodePudding user response:

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.

CodePudding user response:

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

  • Related