I've reduced the problem into the code below.
// test.js
const request = require("request");
const fs = require("fs");
setInterval(async function () {
console.log('before getData');
await getData();
}, 1000)
function getData() {
return new Promise((f, r) => {
const file = fs.createWriteStream(`test.txt`);
request(`https://www.google.com`)
.pipe(file)
.on("error", error => {
r(error);
});
file.on("finish", () => {
console.log('pipe finished');
f();
});
});
}
I'm trying to make it so that the setInterval function has to wait until the data streamed from google into a text file has completed before continuing.
To do this I've wrapped the stream in a promise which should only resolve when the finish
callback is called.
I'd expect pipe finished
to always be logged immediately after before getData
but when I run the script the order is not maintained e.g.
node test.js
before getData
pipe finished
before getData
pipe finished
before getData
before getData
pipe finished
pipe finished
before getData
pipe finished
before getData
pipe finished
before getData
before getData
pipe finished
pipe finished
...
From the debugger it appears that the setInterval function is called often again before the stream is complete so my question is why doesn't the getData
function block the execution until the stream is complete?
CodePudding user response:
set interval calls the same function every x
ms, it does not care if the previous function has finished or not , you would need to use setTimeout
in order to make sure that after the current function the next function is called in x
ms
// test.js
const request = require("request");
const fs = require("fs");
setTimeout(recall,1000)
async function recall(){
await getData()
setTimeout(recall, 1000)
}
function getData() {
return new Promise((f, r) => {
const file = fs.createWriteStream(`test.txt`);
request(`https://www.google.com`)
.pipe(file)
.on("error", error => {
r(error);
});
file.on("finish", () => {
console.log('pipe finished');
f();
});
});
}
CodePudding user response:
callback is called and forgotten by setInterval or setTimeout
Because set interval is not calling the recall, it puts that call to events loop and will call after the time period. It will not check if call was successful, how long it took etc. If you will call function on interval e.g. every 10ms and your function takes 1sec. to execute, every 10ms you will start new execution of function etc.
if you want to execute function on interval and wait till function is executed before starting the interval period, clear interval before executing the function, execute the function, start interval for next execution. You may do the same with setTimeout instead though while in such pattern you don't really need "interval".