Synchronize window.setTimeout callback - javascript

setTimeout(function() {
console.log("1");
}
console.log("2");
Basically, what I want to output "1" before "2". How do I synchronize the callback function with the current "caller" thread?

You can't hold up the thread in JavaScript (other than the alert and confirm built-ins), so the only ways to make your console.log("2") happen after your console.log("1") are:
Put it in the timeout function:
setTimeout(function() {
console.log("1");
console.log("2");
}, delay);
...or in another function that that timeout function calls, although as you already have a function for the setTimeout, it's unclear (other than code organization) why you'd need a separate one.
Put it in a separate function you pass to setTimeout with a longer delay:
setTimeout(function() {
console.log("1");
}, delay);
setTimeout(function() {
console.log("2");
}, longerDelay);
...being careful that longerDelay really is sufficiently longer than delay that you don't end up with a bit of chaos around scheduling.
Note I said "the thread" above. Unless you're using web workers, which have a specific syntax, JavaScript on browsers is single-threaded. Two JavaScript functions cannot run simultaneously, and aside from edge case browser bugs around alert and ajax completions and the like (at least some versions of Firefox run your ajax completion callback while you have a function waiting on alert; strange but true, and nothing you can rely on cross-browser or even cross-version), you can't pause one JavaScript function in its tracks while another JavaScript function runs.

Try something like:
setTimeout(function() {
console.log("1");
callback();
}
function callback(){
console.log("2");
}

Related

Javascript: what is a callback?

In this article which I was referred to the following statement is made:
Callbacks are a way to make sure certain code doesn’t execute until other code has already finished execution.
The article then goes on to illustrate this with an example:
function doHomework(subject, callback) {
alert(`Starting my ${subject} homework.`);
callback();
}
doHomework('math', function() {
alert('Finished my homework');
After this the articles states:
As you’ll see, if you type the above code into your console you will get two alerts back to back: Your ‘starting homework’ alert, followed by your ‘finished homework’ alert.
The implication seems to be that by using a callback the desired order of code execution has been ensured. That is you start your homework before you finish it. However, I feel I may have misunderstood the whole point of the article and therefore still do not understand callbacks and asynchronous code because when I slow down the first part of the doHomework function using setTimeout() the code executes (or at least returns) in the opposite order:
function doHomework(subject, callback) {
setTimeout(function(){
console.log(`Starting my ${subject} homework.`);
}, 500);
callback();
}
doHomework('math', function() {
console.log('Finished my homework');
});
The result I get from that is:
steve#Dell ~/my-app $ node app.js
Finished my homework
Starting my math homework.
});
I am using node here (hence console.log() replaces alert()) but I do not think that is relevant.
It seems to me I have missed something quite fundamental and need to try and access what it is that I am trying to understand before I then try and understand it.
Any assistance on this journey would be greatly appreciated.
After getting great feedback I think the homework analogy was not helpful so I am now using the first code example in the article I referenced. The article gives this code:
function first(){
// Simulate a code delay
setTimeout( function(){
console.log(1);
}, 500 );
}
function second(){
console.log(2);
}
first();
second();
The above returns 2 then 1 in the console.
I tried (without success) to reverse the return order to 1 then 2 with this:
function first(callback){
setTimeout(function(){
console.log(1);
}, 500);
callback();
}
function second(){
console.log(2);
}
first(second);
The answer I got from Cleared (before it was edited) was to put the callback() inside the setTimeout() function. He used the homework example but here it is with this example:
function first(callback){
setTimeout(function(){
console.log(1);
callback();
}, 500);
}
function second(){
console.log(2);
}
first(second);
I think that is closer to what I am imagining the article was getting at. It seems to make sense although I guess the precise context of what you are doing and what you want to happen determine what is right or wrong.
In general, the call to the callback is not at the end of the function, but rather after you have done the important things.
So if I understand your question, the doHomework-function should start doing homework (which takes time, in this case 500ms), and then the homework is finished. So the important things in your case is the console.log('Starting my ${subject} homework.'); which "takes 500ms" (since this is the time you need to do the homework).
Therefore, you should put the call to the callback right after console.log('Starting my ${subject} homework.');, i.e.
function doHomework(subject, callback) {
setTimeout(function(){
console.log(`Starting my ${subject} homework.`);
callback();
}, 500);
}
doHomework('math', function() {
console.log('Finished my homework');
});
Generally, you would call the callback function when you are finished doing whatever it is you are doing.
So you have the code inside and outside your setTimeout function backwards.
function doHomework(subject, callback) {
console.log(`Starting my ${subject} homework.`);
setTimeout(function(){
console.log(`Finished my ${subject} homework.`);
callback();
}, 500);
}
What exactly is callback?
Callback meaning function-in-function like recursive.
Let me give you an example:
Every day we eating then sleeping. But in JS code, JS is an impatient language unlike PHP. This is the example code:
// Consuming 3s to eating(just an example, not really 3s)
function eating() {
setTimeout(function() {
console.log('Eating...');
}, 3000);
}
// Then go to sleep
function sleep() {
console.log('Z..Z..Z');
}
eating();
sleep();
But you sleep immediately after...(When we run the code it runs the sleep first then eating())
To assure that everything works in order, meaning you only go to bed when done eating. So we need the eating() to tell when it's done to start the sleep():
// Consuming 3s to eating(just an example, not really 3s)
function eating(callback) {
setTimeout(function() {
console.log('Eating...');
callback() // the function which will be proceeded after "Eating..."
}, 3000);
}
// Then go to sleep
function sleep() {
console.log('Z..Z..Z');
}
// call the function
eating(function() {
sleep();
});
Yeah! Right now I think you can use callback in your code!
Where you can see callback?
You can see it in every JQuery code:
$("#hide").click(function(){ //the click() function call the function inside it which is callback
$("p").hide();
});
$("#show").click(function(){
$("p").show();
});
Callbacks in Javascript are used in asynchronous programming, where you can't ensure that the code above is running before the code below, like loading files from a server asyncronous.
The problem is, that with normal sequential programming, you can not ensure, that the data you fetch is fully loaded when the programm is running (i.e. if you run the script, one time the variable could be setted, another time it could be undefined, cause async task is still running), so you set a callback function, which gets connected to different states, ie. success or error on ajax call. The difference to normal programming flow is, your programm does not stop till it has loaded the data (or in your case, the timeout doesnt pause your program, the code afterwards is computed and the timeout can run of anytime, if you dont use a fix value).
So, to ensure that your code will run when the needed logic finishes, you have to pass a callback function, which is executed when the needed state is fulfilled (i.e. success/error on loading tasks, or a timeout is "finished".
The homework example IMO isnt the best sample, cause it doesnt touch the real use cases, as it always "waits" 500ms.
In your example the problem is, your "callback" is out of the "asyncronous" part of code, so its executed directly after starting the timeout, even if the timeout still is "running". Maybe your thinking of SetTimeout is the problem, in my javascript beginnings I thought its more like "pause for 500ms", but its "execute the scoped code after waiting for 500ms out of the normal code flow"
Here are some more informations, I can recommend the whole page, even if your not javascript noob ;)
https://javascript.info/callbacks

Javascript Chrome console while

I was trying to create a loop in Chrome console with Javascript that executes the same function all the time. Instead it doesn't output anything and it actually just increases Chromes memory size until it crashes. Any advice on what's going wrong here?
while(true){
window.setTimeout(function (){
console.log("Hello");
}, 4000)}
You're creating an immense number of setTimeout events, all of which are created immediately in rapid succession and scheduled to be invoked 4000 ms after their creation.
Seems like you're looking for .setInterval() to perform a continuous invocation.
window.setInterval(function() {
console.log("Hello");
}, 4000);
To do it with setTimeout, you'd still not use any kind of imperative loop. You'd have the callback set up another setTimeout when it runs.
window.setTimeout(function f() {
console.log("Hello");
setTimeout(f, 4000);
}, 4000);
I gave the callback function the name f so that it could be used for the next timer.
In general, you don't "pause" your script. You schedule things to be done at a later time, and allow code to continue running until then. That's why you had a problem. The scheduled timer didn't pause anything, so the loop just keep running at full speed.

Delay jquery function inside the function?

Is it possible to make a function 'idle' for a couple of seconds while it is being executed?
I tried with
setTimeout( function(){
$("#nytLevel").hide();
} , 3000 );
But the rest of the function would just executed.
Below the setTimeout I start a function
function timer(){
myVar = setTimeout( function(){
console.log("SLOW");
} , 10000 );
}
but when 10 seconds have passed it'll console log "SLOW", but it should console log it 13 seconds after because I've put a setTimeout to 3 seconds.
setTimeout() just schedules something to run in the future and the rest of your Javascript continues to run. It does not block further Javascript execution. This is often called an "asynchronous" operation. It runs in the background and will call a callback sometime in the future when it has completed its work. It is also referred to as "non-blocking" because it does not block the rest of your Javascript execution.
Anything you want to not run until the setTimeout() fires must be put inside the setTimeout() callback or called from there.
// define function
function timer(){
myVar = setTimeout(function() {
console.log("SLOW");
}, 10000);
}
// schedule first timer
setTimeout(function() {
$("#nytLevel").hide();
// now start second timer
timer();
}, 3000);
It's worth mentioning that jQuery has a .delay() method that works with animations and other functions put in the queue and it can sometimes streamline your code. In the case above, you could do this:
$("#nytLevel").delay(3000).hide().delay(10000).queue(function(next) {
console.log("SLOW");
next(); // keep the queue moving in case there's something else in the queue
});
Please note that .delay(xxx) only works with jQuery methods that themselves use the queue (such as animations) or with methods you put in the queue yourself using .queue() (as I've shown above).
setTimeout() is an asynchronous function, meaning that code will not pause until the setTimeout() time is completed. If you want code to be delayed along with the setTimeout(), you can put the other code inside of the initial setTimeout()
setTimeout( function(){
$("#nytLevel").hide();
myVar = setTimeout( function(){
console.log("SLOW");
} , 10000 );
} , 3000 );
I wouldn't recommend this, but you could fashion a recursive function to do what you wanted, using a flag to dictate before or after timeout. In the below example you'd call it like this runAfterTimeout() or runAfterTimeout(false)
function runAfterTimeout(run) {
if (! run) {
console.log('about to wait 10 seconds');
setTimeout(function(){runAfterTimeout(true)},10000);
return;
}
console.log('this section runs after 10 seconds');
setTimeout(function(){$("#nytLevel").hide();},3000);
}
Fiddle: https://jsfiddle.net/m9n1xxra/
Bear in mind, timeouts are not 100% accurate. The engine will look for an appropriate break in execution to execute what you want, but if the engine is in the middle of something else, that will execute first.

Why does the following JS function wreck the browser process?

var wait = function (milliseconds) {
var returnCondition = false;
window.setTimeout(function () { returnCondition = true; }, milliseconds);
while (!returnCondition) {};
};
I know there have been many posts already about why not to try to implement a wait() or sleep() function in Javascript. So this is not about making it usable for implementation purposes, but rather making it work for proof of concept's sake.
Trying
console.log("Starting...");wait(3000);console.log("...Done!");
freezes my browser. Why does wait() seemingly never end?
Edit: Thanks for the answers so far, I wasn't aware of the while loop never allowing for any other code to execute.
So would this work, then?
var wait = function (milliseconds) {
var returnCondition = false;
var setMyTimeOut = true;
while (!returnCondition) {
if (setMyTimeOut) {
window.setTimeout(function() { returnCondition = true; }, milliseconds);
setMyTimeOut = false;
}
};
return;
};
JavaScript is executed in a single thread. Only when an execution path exits can another execution path begin. Thus, when you launch your wait(3000), the following happens:
returnCondition is set to false
a timeout is scheduled
an infinite loop is started.
Each <script> tag, each event being handled, and each timeout (and also UI refresh, in case of a browser) initiate a separate execution path. Thus, a timeout of 3000 is not guaranteed to run in 3000ms, but at any time after 3000ms when the engine is "free".
The wait function never exits, so your script's execution path never ends, and the scheduled timeout's turn never comes.
EDIT:
That means, once a <script> tag has begun, or Node.js has started executing a JavaScript file, the execution has to reach the bottom before anything else can happen. If a function is started as a result of an event or a timeout, that function needs to exit before anything else can happen.
<script>
console.log("script top");
function theTimeout() {
console.log("timeout top");
// something long
console.log("timeout bottom");
}
setTimeout(theTimeout, 0);
setTimeout(theTimeout, 0);
console.log("script bottom");
</script>
There are three execution paths here. The first is the <script> tag's: it starts with printing "script top", schedules two timeouts (for "right now"), then prints "script bottom", and then the end of <script> is reached and the interpreter is idle. That means it has time to execute another execution path, and there are two timeouts is waiting, so it selects one of them and starts executing it. While it is executing, again nothing else can execute (even UI updates); the other timeout, even though it was also scheduled at "immediately", is left to wait till the first timeout's execution path ends. When it does, the second timeout's turn comes, and it gets executed as well.
JavaScript is single threaded. When you call setTimeout the method you passed in as an argument is placed to the async call stack. It means the very next line of code in your block is executing immediately after the setTimeout call and the function you passed in as an argument will execute after your wait method exits.
Your while loop is waiting for a condition which will never happen while the wait function is running because the function which will set your flag will not run until the wait function is done.
The correct way to implement wait is:
var wait = function (milliseconds, onEnd) {
window.setTimeout(function () { onEnd(); }, milliseconds);
};
wait(1000, function(){alert('hi')});
Here you pass in a callback function which will execute after the timeout.
If you have multiple async style calls you can use promises. Promises will make your code easy to read and it will be easy to chain multiple async calls together. There are very good promise librarians: JQuery has $.Deferred built into it but you can use Q if you are writing node.js code.
A promise style implementation would look something like this:
var wait = function (milliseconds) {
var onEnd = null;
window.setTimeout(function () { onEnd(); }, milliseconds);
return {
then: function(action){
onEnd = action;
}
}
};
wait(1000).then(function(){alert('hi')});
https://api.jquery.com/jquery.deferred/
https://github.com/kriskowal/q
The following book helped me a lot to understand this subject:
Async JavaScript: Build More Responsive Apps with Less Code by Trevor Burnham
https://pragprog.com/book/tbajs/async-javascript

Recursive setTimeout calls mysteriously stop running

I want to call a function in JavaScript continuously, for example each 5 seconds until a cancel event.
I tried to use setTimeout and call it in my function
function init()
{ setTimeout(init, 5000);
// do sthg
}
my problem is that the calls stops after like 2 min and my program is a little bit longer like 5 min.
How can i keep calling my function as long as i want to.
thanks in advance
The only conceivable explanations of the behavior you describe are that:
As another poster mentioned, init is somehow getting overwritten in the course of executing itself, in the // do sthg portion of your code
The page is being reloaded.
The //do sthg code is going into some kind of error state which makes it looks as if it not executing.
To guarantee that init is not modified, try passing the // do sthg part as a function which we will call callback:
function startLoop(callback, ms) {
(function loop() {
if (cancel) return;
setTimeout(loop, ms);
callback();
}());
}
Other posters have suggested using setInterval. That's fine, but there's
nothing fundamentally wrong with setting up repeating actions using setTimeout with the function itself issuing the next setTimeout as you are doing. it's a common, well-accepted alternative to setting up repeating actions. Among other advantages, it permits the subsequent timeouts to be tuned in terms of their behavior, especially the timeout interval, if that's an issue. If the code were to be rewritten using requestAnimationFrame, as it probably should be, then there is no alternative but to issue the next request within the callback, because requestAnimationFrame has no setInterval analog.
That function is called setInterval.
var interval = setInterval(init, 5000);
// to cancel
clearInterval(interval);

Categories

Resources