I have an array with multiple delays stored in it: myArray[8000,4000,3000,6000,5000]. I need for setTimeout/setInterval to run each delay and then execute a specific piece of code. So for example:
myArray[0]=8000;
myArray[1]=4000;
myArray[2]=3000;
myArray[3]=6000;
myArray[4]=5000;
for(var k=0;k<5;k++)
{
setTimeout(function() {
console.log("CODE TO BE EXECUTED");
}, diffArray[k]);
}
So the end result would be wait 12 seconds run code, wait 4 seconds run code, wait 3 seconds run code wait 6 seconds run code, and wait 5 seconds and run code. The current code runs them all at the same time.
I know that this most likely needs to be done with recursion, I've tried a few things as far as getting it to work, but no luck. I got it to work one way but it unfortunately locked the UI thread which I will need to perform other actions in the UI while this is running. Any help with this would be greatly appreciated!
Run setTimeout sequentially. You are running all setTimeout at same time.
myArray[0]=8000;
myArray[1]=4000;
myArray[2]=3000;
myArray[3]=6000;
myArray[4]=5000;
var k =0;
function repeat(){
if(k == myArray.length) return;
setTimeout(function() {
repeat();
console.log("CODE TO BE EXECUTED");
}, myArray[k]);
k++;
}
You should make another function so that the k variable is copied each time because setTimeout is an async operation:
var func = function(k)
{
setTimeout(function() {
console.log("CODE TO BE EXECUTED");
}, diffArray[k]);
}
for(var k=0;k<5;k++)
{
func(k)
}
You mention 12 seconds, but there is not a value that large. If you want the code to run 8sec, 12sec,15sec,21sec, and 26sec, then:
var delay =0;
for(var k=0;k<5;k++){
delay+=myArray[k];
setTimeout(function() {
console.log("CODE TO BE EXECUTED");
}, delay);
}
Related
I had the following question on an interview. cannot see what's wrong with it.
The following code attempts to run 10 tasks sequentially and have a timeout of 1 second after each task. Given the following piece of code, please identify issues with it, and write a correct implementation for the original intention.
for (let i = 0; i < 10; i++) {
setTimeout(function() {
// Running some asynchronous tasks here
// ...
console.log("completed task id " + i);
}, 1000)
}
You can try with async function awaiting for promise will be resolved.
async function toDo() {
for (let i = 0; i < 10; i++) {
await new Promise(res => {
setTimeout(() => {
// Running some asynchronous tasks here
// ...
console.log('completed task id ' + i)
res()
}, 1000)
})
}
}
toDo()
This starts all the timeouts immediately when the loop runs, so all the messages will be in 1 second, instead of 1 second between them.
One way to fix it is to make the timeouts depend on i.
for (let i = 0; i < 10; i++) {
setTimeout(function() {
// Running some asynchronous tasks here
// ...
console.log("completed task id " + i);
}, 1000 * (i + 1))
}
This is the simplest way to do it, it starts each task 1 second after the previous one started.
But if the tasks performed some long operation, and you didn't want to start the next task until 1 second after the previous one completed, you would need a more complex implementation. Instead of using a loop, you would have to have the task increment i and call setTimeout() itself to schedule the next iteration.
function timeout_fn(i) {
// do slow operation
console.log("completed task id " + i);
i++;
if (i < 10) {
setTimeout(() => timeout_fn(i), 1000);
}
}
setTimeout(() => timeout_fn(0), 1000);
Issues:
setTimeout schedules a function to be run after the specified delay. Note that all setTimeouts are scheduled at the same time, they don't wait for each other. This is what is meant by "asynchronous". Thus, all of your setTimeout calls are with a delay of 1000 ms, and all of them will run consecutively after only 1000ms.
If you really are running other asynchronous tasks in the callback to setTimeout, the console.log will not wait for them unless you tell it to. I can only guess, but make sure you use an await, an async function or another callback.
for (let i = 0; i < 10; i++) {
setTimeout(function() {
// Running some asynchronous tasks here
// ...
console.log("completed task id " + i);
}, 1000 * i) //multiply i by 1000 to wait 1,2,3,4... seconds
}
Maybe another solution will be to use the setInterval function with a 1000ms interval and call setTimeout with 10 seconds waiting times to clear the interval :
const myInterval = setInterval(function() {
// some async stuff here
}, 1000);
setTimeout(function() {
clearInterval(myInterval)
}, 10000);
This question already has answers here:
setTimeout blocked by continuous AJAX requests?
(2 answers)
Closed 4 years ago.
Hie!
I'm doing a test task, creating "slow_guard" function that should consoles warning message if another function passed to slow_guard executes too long.
Here is my code (codepen):
function slow_guard(timeout, fn) {
var timer = setTimeout(function() {
console.log('Function lasts for more than ' + timeout/1000 + ' sec.!');
}, timeout + 1);
var start = new Date().getTime();
fn();
var end = new Date().getTime();
var time = end - start;
console.log('Execution time: ' + time);
clearTimeout(timer);
// if(time < timeout) { clearTimeout(timer); }
}
function longFunction() {
for (i = 0; i < 7999000; ++i) {
// do something
}
}
slow_guard(1000, longFunction);
But it doesn't work. It seems like clearTimeout doesn't wait for loop end and executes immediately.
If I use additional check using Date it works fine (you can check it replacing the code clearTimeout(timer) with the lower commented one).
Why does this happen?! Explain, please!
setTimeout will queue a function to run later, but if you're in the middle of executing another function, it won't be interrupted to resolve the queued function.
The JavaScript engine will finish running slow_guard (including the clearTimeout call) before it checks the queue to see if there are any timed functions waiting to go (which there won't be because you just cleared it).
In my code, I'm trying to put a certain delay before continuing to the rest of the code. Pretty basic. I'm using a custom sleep function because javascript's native sleep function is not working at all. I'm actually working in app script in google spreadsheets so maybe that's why. But the following code is in the <script> tag of the html file in spreadsheet app script.
Anyway, when I use sleep(), it is being executed before the setTimeout
function get_ids(db){
window.alert("before window.ids is saved?");
google.script.run.withSuccessHandler(getIdsFromAppscript).getIdsFromModel(db);
//this returns a result to getIdsFromAppscript but the following code doesn't wait
//for the result to be returned so I want to use sleep before the ids
//variable is returned by get_ids
setTimeout(function(){
window.alert("checking if ids is saved after 10s?");
window.alert("In timeout ids="+window.ids);
var ids= window.ids; //is non empty
},10000);
sleep(10000);
var ids= window.ids;
window.alert("after wait");
window.alert("after sleep ids="+ids); //is empty but should be non empty
return ids; //=window.ids , Need to return a non-empty result
}
function getIdsFromAppscript(result){
window.ids=result;
}
and the sleep function:
function sleep(ms) {
var start = new Date().getTime(), expire = start + ms;
while (new Date().getTime() < expire) { }
return;
}
Current Order of output based on window.alert():
1) before window is saved?
2) after sleep
3) after sleep ids= //basically empty which shouldn't be the case
4) checking if ids is saved after 10s?
5) In timeout ids= [.....] //non empty list
However, my desired output order is:
1) before window is saved?
2) checking if ids is saved after 10s?
3) In timeout ids= [.....] //non empty list
4) after sleep
5) after sleep ids= [...] //should be a non empty list
The reason why I'm writing setTimeout is to show that after 10 seconds, the result is being stored in window.ids however even after I give a sleep for 10 seconds, or even 30 seconds, I can't get the result from window.ids.
What exactly am I doing wrong here? Thanks in advance~
Java Script, especially through the V8 engine does not sleep. Sleeping causes the entire thread that JavaScript runs on to stop, which breaks the whole point of asynchronocy. setTimeout() only waits to run the function you push into it for the time you also put into it. It doesn't stop the rest of the executions, and whatever happens first will happen first.
If it's important to you that something happens in order, always, then you need to use callbacks or promises.
An example in code could be:
function doTimeout(ms) {
setTimeout(function(){
window.alert("checking if ids is saved after 10s?");
window.alert("In timeout ids="+window.ids);
var ids= window.ids; //is non empty
},ms);
}
function sleep(ms, callback) {
var start = new Date().getTime(), expire = start + ms;
while (new Date().getTime() < expire) { }
callback(ms);
}
sleep(10000, doTimeout);
Javascript is single threaded. You must return from your code for scripts in other threads to execute. Script in other threads includes functions to handle a timeout event, functions called when promises are kept or fail, and call back functions provided for asynchronous requests made using an XMLHttpRequest object.
Writing a function and calling it sleep() does not change this. You could have called it waitingForGodot() for all the difference it would make. What the code you provided does is to spend a lot of time looping in the thread it was called in. It does not relinquish control and blocks all other scripts from executing. If it goes on for long enough my browser will ask me if I wish to abort the (as in your) script.
I have included two examples below showing that your sleep function blocks the entire Javascript engine. When I use your sleep function, the interval function does not get executed even though I have set an interval of 100 ms and the output is delayed by 10 seconds. However, in the second example the output does get printed immediately at the correct interval. This shows your sleep function is blocking the entire execution engine and that explains why your ids array is empty.
function sleep(ms) {
var start = new Date().getTime(),
expire = start + ms;
while (new Date().getTime() < expire) {}
return;
}
function get_ids() {
document.write("before window.ids is saved?" + "<br>");
var counter = 0;
setInterval(function() {
while (counter < 100) {
document.write("checking if ids is saved after 10s?" + "<br>");
counter = counter + 1
}
}, 100);
sleep(10000);
documen.write("after wait");
}
document.write("Start");
get_ids()
document.write("End");
In this example I have commented out your sleep function and as expected the output gets printed every 100 ms:
function sleep(ms) {
var start = new Date().getTime(),
expire = start + ms;
while (new Date().getTime() < expire) {}
return;
}
function get_ids() {
document.write("before window.ids is saved?" + "<br>");
var counter = 0;
setInterval(function() {
while (counter < 100) {
document.write("checking if ids is saved after 10s?" + "<br>");
counter = counter + 1
}
}, 100);
//sleep(10000);
documen.write("after wait");
}
document.write("Start");
get_ids()
document.write("End");
Suppose I have the following code in node.js:
process.on('SIGTERM', function () {
process.exit(0);
});
for (var i = 0; i < 100; i++) {
console.error(i);
}
Will the code always print all the numbers up to 100?
This is easy enough to test:
process.on('SIGTERM', function () {
console.log('*** GOT SIGTERM ***');
process.exit(0);
});
process.kill(process.pid);
for (var i = 0; i < 100; i++) {
console.error(i);
}
The results show that, indeed, the for loop does run to completion, but this is misleading. The for loop blocks I/O. Because Node is single-threaded, process.exit(0) doesn’t get called until the for loop is done.
A more illustrative example:
process.on('SIGTERM', function () {
console.log('*** GOT SIGTERM ***');
process.exit(0);
});
process.kill(process.pid);
setTimeout(function() {
for (var i = 0; i < 100; i++) {
console.error(i);
}
}, 1000);
Here we use setTimeout to wait 1 second before doing the for loop. Node’s event loop will continue to run during that time, so the process.on('SIGTERM') will be called before the for loop begins. And the results are different: the for loop does not run at all.
Once process.exit(0) is called, the app ends and nothing else is executed. The difference between the two examples is when process.exit(0) is called.
This code expands on the dynamic.js script. The dynamic.js runs like this: start, then, run, and then the run callback is the dynamic loop. That runs fine. My code doesn't want to loop at the end of the run callback, it wants to loop in the middle, so that I can run more code afterwards. So it's start, then, loop, then, run. It seems that casper is not waiting for my loop to finish before exiting. The loop terminates at different points every time that it runs, and I never see the "after dynamic loop" echo out. Here is some sample output (it ends anywhere between 2 and 8 loops, usually), and then the code:
Output:
start main
start dynamic loop
0
Something.
1
Something.
2
Something.
3
Something.
4
Something.
5
Something.
Code:
var casper = require('casper').create();
var limit = 10;
var i = 0;
// dynamic loop
var loop = function () {
if (i < limit) {
this.echo(i);
this.start("http://www.something.com", function() {
this.echo(this.evaluate(function () { return document.body.innerText; }));
});
i++;
this.run(loop);
} else {
this.echo("dynamic loop done");
this.exit();
}
}
// main flow
casper.start('http://www.something.com', function() {
this.echo("start main");
});
casper.then(function () {
casper.start().then(function() {
this.echo("start dynamic loop");
});
casper.run(loop);
});
casper.then(function () {
this.echo("after dynamic loop");
})
casper.run();
You should use casper.start and casper.run only once in your script. However, you can use them. If you do you run into "undefined" behavior if you nest them in another control flow. I find it is best to use casper.thenOpen and casper.then as a replacement for casper.start and casper.run:
// dynamic loop
var loop = function () {
if (i < limit) {
this.echo(i);
i++;
this.thenOpen("http://www.something.com", function() {
this.echo(this.evaluate(function () { return document.body.innerText; }));
});
this.then(loop);
} else {
this.echo("dynamic loop done");
}
}
// main flow
casper.start('http://www.something.com', function() {
this.echo("start main");
});
casper.then(loop);
casper.then(function () {
this.echo("after dynamic loop");
})
casper.run();
You may have multiple casper instances in one script, but then you would need to synchronize them somehow.
Your script may need a little fix without refactoring. Just remove this.exit(); from loop. You exit prematurely. But I still strongly suggest that you refactor your script.