Delay using readline in nodejs - javascript

function readFile(){
var lineReader = require('readline').createInterface({
input: require('fs').createReadStream(FILE_PATH)
});
lineReader.on('line', function (line) {
setTimeout(() => {
console.log("HEYYYYY");
}, 10000);
});
}
Why does this only waits 10 seconds once , and the prints 'hey' ? I want to print hey each 10 seconds but it's not working. No idea why.
Edit: This is going to be repeated by the amount of lines that there are on a file (look at the listener 'line') I need to delay 10s between each line.

I had the same problem and I solved it with the "Example: Read File Stream Line-by-Line" found in: https://nodejs.org/api/readline.html
In your case it would be something like this:
const fs = require('fs');
const readline = require('readline');
async function processLineByLine() {
const fileStream = fs.createReadStream(FILE_PATH);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
// Note: we use the crlfDelay option to recognize all instances of CR LF
// ('\r\n') in input.txt as a single line break.
for await (const line of rl) {
// Each line in input.txt will be successively available here as `line`.
console.log(`Line from file: ${line}`);
await sleep(10000)
}
}
function sleep(ms){
return new Promise(resolve=>{
setTimeout(resolve,ms)
})
}
This example would print you a line every 10 seconds.

It's not waiting 10 seconds once. its just that each line is read so fast, there's almost not difference in the start time. you can add a variable that increase the delay by 10 seconds in each callback so you each line is print each 10 seconds.
function readFile(){
var delay = 0;
var lineReader = require('readline').createInterface({
input: require('fs').createReadStream(FILE_PATH)
});
lineReader.on('line', function (line) {
delay += 10000;
setTimeout(() => {
console.log("HEYYYYY");
}, 10000+delay);
});
}

Related

How long should it take to process big files in node.js?

I am not used to working with big files but I was wondering how long does it approximately takes to read and write in node.js when using files that are 2-3GB big or ~ 7.5 million lines.
my current implementation takes about ~ 12 minutes or 737859.276ms
I know that it's hard to approximate and depends on context but I wanted to make sure if it could be done faster.
function LogParser(filePath, outputFile, cb) {
try {
const rl = createInterface({
input: createReadStream(filePath),
crlfDelay: Infinity,
});
writer.pipe(createWriteStream(outputFile));
rl.on('line', (line) => {
// Gets line and splits it by " - " where the ip is the first value
const IPAddress = line.split(' - ')[0];
const locationData = lookup(IPAddress); // translate to data object with region and country and city
const userAgentData = parser(line); // get userAgent data
const result = {
// object with data inside
};
writer.write(result)
});
rl.on('close', () => {
writer.end()
});
} catch (e) {
throw new Error(e.message);
}

How to update in html page during nodejs readline process

I want to dynamically change the content of a element in my html page during nodejs readline process.
Here is a jsfiddle example to shown the display effect I want to fulfill:
https://jsfiddle.net/09kuyn7v/
But I want to dynamically display lines from my local file, but not from an array defined within the function as in the jsfiddle example.
I have used readline module in my read-file-version clickTest() function:
function clickTest(){
var fs = require('fs');
var lineReader = require('readline').createInterface({
input: fs.createReadStream(filePath)
});
lineReader.on('line', function(line){
document.getElementById("demo").innerHTML += line;
});
}
But when I click the button, the page was just like being freezed and then the lines were displayed simultaneously (not one by one as shown in the jsfiddle example above).
First of all, every time you call that function you do require('readline') and require('fs') so I would move that up the script.
I would suggest two approaches:
Pausing read
var readline = require('readline');
var fs = require('fs');
function clickTest(){
var lineReader = readline.createInterface({
input: fs.createReadStream(filePath)
});
lineReader.on('line', function(line){
// pause emitting of lines...
lineReader.pause();
// write line to dom
document.getElementById("demo").innerHTML += line;
// Resume after some time
setTimeout(function(){
lineReader.resume();
}, 1000);
});
lineReader.on('end', function(){
lineReader.close();
});
}
This approach should read one line, then pause and resume after some time you specify.
Buffering lines
var readline = require('readline');
var fs = require('fs');
var lines = [];
function clickTest(){
var lineReader = readline.createInterface({
input: fs.createReadStream(filePath)
});
lineReader.on('line', function(line){
lines.push(line)
});
lineReader.on('end', function(){
lineReader.close();
printLine(0);
});
}
function printLine(index){
// write line to dom
document.getElementById("demo").innerHTML += lines[index];
if (index < lines.length - 1){
setTimeout(function(){
printLine(index + 1);
}, 1000);
}
}
This approach will save all the lines into an array and then slowly prints them out.
Please note that I haven't got node-webkit to actually test it, so you might find a bug in the code, but it should give you general idea

Show file lines with delay in Node.js

I am trying to make a program in node.js that reads a text file line by line and shows each of them with a delay of 2 seconds. The code I am testing is the following.
var fs = require('fs'),
readline = require('readline');
var FileSystem_Lectura=function()
{
this._rd=null;
}
FileSystem_Lectura.prototype.abrirArchivoCSV=function(nombreArchivo)
{
this._rd = readline.createInterface
({
input: fs.createReadStream(nombreArchivo),
output: process.stdout,
terminal: false
});
}
FileSystem_Lectura.prototype.leerArchivoCSV=function()
{
self=this;
this._rd.on('line',self.mostraLineasDelay);
}
FileSystem_Lectura.prototype.mostraLineasDelay=function(linea)
{
setTimeout(self.mostraLinea,20000,linea);
}
FileSystem_Lectura.prototype.mostraLinea=function(linea)
{
console.log("Linea:"+ linea);
}
var FS =new FileSystem_Lectura();
FS.abrirArchivoCSV(process.argv[2]);
FS.leerArchivoCSV();
The problem is that settimeout shows me all the lines together, it does not apply the delay. Except for the first line. So, how can I make it work properly?
From already thank you very much
Use pause/resume on your stream :
var fs = require('fs'),
readline = require('readline');
var FileSystem_Lectura=function()
{
this._rd=null;
}
FileSystem_Lectura.prototype.abrirArchivoCSV=function(nombreArchivo)
{
this._rd = readline.createInterface
({
input: fs.createReadStream(nombreArchivo),
output: process.stdout,
terminal: false
});
}
FileSystem_Lectura.prototype.leerArchivoCSV=function()
{
self=this;
this._rd.on('line',self.mostraLineasDelay);
}
FileSystem_Lectura.prototype.mostraLineasDelay=function(linea)
{
this._rd.pause();
setTimeout(self.mostraLinea,2000,linea);
}
FileSystem_Lectura.prototype.mostraLinea=function(linea)
{
console.log("Linea:"+ linea);
this._rd.resume();
}
Also, 2 seconds is 2000ms, not 20000.
This sort of thing is way easier these days:
import {createInterface} from 'readline';
import {createReadStream} from 'fs';
import {pipe, delay} from 'iter-ops';
const file = createInterface(createReadStream('./my-file.txt'));
const i = pipe(file, delay(2000)); //=> AsyncIterable<string>
(async function () {
for await(const line of i) {
console.log(line); // prints line-by-line, with 2s delays
}
})();
Libraries readline and fs are now standard. And iter-ops is an extra module.

nodejs createReadStream start from nth line

I have the following code in order to read a text file line by line with nodejs:
var lineReader = require('readline').createInterface({
input: require('fs').createReadStream('log.txt')
});
lineReader.on('line', function (line) {
console.log(line);
});
lineReader.on('close', function() {
console.log('Finished!');
});
Is there any way to start reading the file from a specific line?
According to the Node.js Docs you can specify both start and end options when creating the stream:
options can include start and end values to read a range of bytes from the file instead of the entire file. Both start and end are inclusive and start at 0
// get file size in bytes
var fileLength = fs.statSync('log.txt')['size'];
var lineReader = require('readline').createInterface({
input: require('fs').createReadStream('log.txt', {
// read the whole file skipping over the first 11 bytes
start: 10
end: fileLength - 1
})
});
A solution i found,
var fs = require('fs');
var split = require('split');
var through = require('through2');
fs.createReadStream('./index.js')
.pipe(split(/(\r?\n)/))
.pipe(startAt(5))
.pipe(process.stdout);
function startAt (nthLine) {
var i = 0;
nthLine = nthLine || 0;
var stream = through(function (chunk, enc, next) {
if (i>=nthLine) this.push(chunk);
if (chunk.toString().match(/(\r?\n)/)) i++;
next();
})
return stream;
}
See
split: https://github.com/dominictarr/split
through2: https://github.com/rvagg/through2

Haskell call Node.js file not working

I am trying to write a program in Haskell that takes in the input as a string of sentences, calls a javascript file with that input, and return the output of that javascript file as the output of the Haskell file. Right now, the output of the javascript file is not printed. It is not clear whether javascript file is called or not.
Here is the script in Haskell:
main :: IO ()
main =
do
putStrLn "Give me the paragraphs \n"
paragraphs <- getLine
output <- readCreateProcess (shell "node try2.js") paragraphs
putStrLn output
Script in Node.js. The desired output is toplines:
var lexrank = require('./lexrank');
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Hi', (answer) => {
var originalText = answer;
var topLines = lexrank.summarize(originalText, 5, function (err, toplines, text) {
if (err) {
console.log(err);
}
rl.write(toplines);
// console.log(toplines);
});
rl.close();
});
I am guessing there is some problem with my way of doing stdin. I am new to Node.js
It took me a really long time but following code works:
Haskell File:
import System.Process
main :: IO ()
main =
do
putStrLn "Give me the paragraphs \n"
paragraphs <- getLine
output <- readCreateProcess (shell "node lexrankReceiver.js") (paragraphs ++ "\n")
putStrLn output
NodeJs File:
// Getting this to work took almost a full day. Javascript gets really freaky
// when using it on terminal.
/* Import necessary modules. */
var lexrank = require('./Lexrank/lexrank.js');
const readline = require('readline');
// var Type = require('type-of-is');
// var utf8 = require('utf8');
// Create readline interface, which needs to be closed in the end.
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// Set stdin and stdout to be encoded in utf8. Haskell passes string as basic
// 8-bit unsigned integer array. The output also needs to be encoded so that
// Haskell can read them
process.stdin.setEncoding('utf8');
process.stdout.setEncoding('utf8');
// If a string is readable, start reading.
process.stdin.on('readable', () => {
var chunk = process.stdin.read();
if (chunk !== null) {
var originalText = chunk;
var topLines = lexrank.summarize(originalText, 5, function (err, toplines, text) {
if (err) {
console.log(err);
}
// Loop through the result to form a new paragraph consisted of most
// important sentences in ascending order. Had to split the 0 index and
// the rest indices otherwise the first thing in newParagraphs will be
// undefined.
var newParagraphs = (toplines[0])['text'];
for (var i = 1; i < toplines.length; i++) {
newParagraphs += (toplines[i])['text'];
}
console.log(newParagraphs);
});
}
});
// After the output is finished, set end of file.
// TODO: write a handler for end of writing output.
process.stdin.on('end', () => {
process.stdout.write('\n');
});
// It is incredibly important to close readline. Otherwise, input doesn't
// get sent out.
rl.close();
The problem with the Haskell program you have is that paragraphs is not a line of input, just a string, so to fix the issue you can append a newline, something like:
output <- readCreateProcess (shell "node try2.js") $ paragraphs ++ "\n"
To find this issue I tried replacing question with a shim:
rl.question = function(prompt, cb) {
rl.on('line', function(thing) {
console.log(prompt);
cb(thing);
})
}
And that worked, so I knew it was something to do with how question handles stdin. So after this I tried appending a newline and that worked. Which means question requires a 'line' of input, not just any string, unlike on('line'), oddly enough.

Categories