In the following javascript code, I set a timer after 2 seconds, in which the handler is a function which alerts 'doneMessage'. When the prompt occurs, the next line should execute after I enter something or cancel the prompt.
function setTimer(doneMessage, n) {
setTimeout(function() {
alert(doneMessage);
}, n);
prompt('Enter a number');
doneMessage = "OUCH!";
}
setTimer("Cookies are done!", 2000);
So if I take more than 2 seconds on the 'prompt', the timer event should occur before the next line is executed. In this case 'doneMessage' should still be "Cookies are done!".
Why is "OUCH" alerted ?
Javascript is a single threaded language.
It cannot run more than 1 tasks at the same time.
Your current task is still being executed but held up by the prompt command.
Once you complete the prompt and exit the setTimer() function then that task is effectively finished.
At that point the doneMessage was set to "OUCH!"
Javascript is now free to do the next task.
Typically, it It loops all the timeout and see if there are any completed timer to execute and put them in a queue to execute next.
If you click on a button, it does not always immediately execute that button. It is place in the queue of task to execute next but given a high priority to make sure it is processed next. If Javascript wasn't currently in middle executing a task your button would be processed immediately.
Use the <input> tag and create your own prompt which is non-thread blocking and you will get the behaviour you want.
Related
I am learning the concept of asynchronous programming in JavaScript (JS). But, I am having a hard time understanding the same. For the last few days, I had been reading various articles on the internet to understand it, but I am unable to grasp the idea.
So, here are the doubts I have:
setTimeout(function(){ alert("Hello 1"); }, 3000); // .....(i)
console.log("Hi!"); // .....(ii)
setTimeout(function(){ alert("Hello 2"); }, 2000); // .....(iii)
Consider the above code. I learnt that JS uses a call-stack and an event-queue to order the execution of instructions. In the above code, when the JS interpreter sees the (i) line, it will enqueue that setTimeout into the event-queue, then moves to (ii), puts it in the call-stack, executes it, then moves to (iii), where it again enqueues the setTimeout into the event-queue (and this queue is not empty), right?
If what I had written in the above question is correct, then once we get to the end of the code since the call-stack is empty the setTimeouts enqueued into the event-queue get executed one by one, right? - That means if we assume it took (say) 10ms to come to the end of the code, then since the event-queue has the setTimeout (i) in the front, it waits for 3s, then pops the alert: "Hello 1", at the time = 3010ms, the dequeues it, and similarly the setTimeout (iii) gets executed after 2 more seconds and then the alert: "Hello 2" pops at the time = 5010ms, right?
Let's suppose that instead of setTimeouts at (i) and (iii), we had addEventListener()'s with some call-back functions. Even in this case, will the call-back functions of the event listeners be enqueued in the event-queue? I feel they don't get enqueued because we could have triggered the call-back of (iii), before the call-back of (i). So, what exactly happens in this case? Is there anything else other than the call-stack and event-queue that somehow stores the information about them and triggers their call-backs accordingly?
In a nut-shell how exactly are the instructions ordered? What exactly happens in the background?
I would be really thankful for a comprehensive answer. It would be great if you can also provide links to some comprehensive materials on this topic.
Thank you for the help!
As you might be aware by now JavaScript engine executes on a single thread, so how are asynchronous operations handled? You are partially true in the below statement, but there is more to it :
Consider the above code. I learnt that JS uses a call-stack and an
event-queue to order the execution of instructions.
True, we do have a call stack and an event loop. But we also have a WEB APIs environment, Call-back Queue and a Micro-task Queue.
Whenever there is any asynchronous task, it moves to the WEB API Environment, for example, when you have an tag with a very large image in the "src" attribute, this image is not downloaded synchronously, because that would block the thread, instead it is moved into the WEB API Environment where the image is loaded.
<img src="largeimg.jpg">
Now, if you want to do something once the image is loaded, you will need to listen to the image's 'load' event.
document.querySelector('img').addEventListener('load', imgLoadCallback);
Now once the image has been loaded, this callback function is still not executed, instead now it is moved into the callback queue. The callback function waits in the callback queue, the event loop will check for synchronous code, and wait until the call stack is empty. Once the call stack is empty, the event loop will push in a first in callback function into the call stack in one event loop tick. And that is when that call back function is executed.
However, this changes when there are micro-tasks such as Promises. When there is a promise, it is sent to the microtask queue. Microtasks will always have priority over the callbacks and they can and will halt the callbacks until they are executed, event loop will always prioritize microtasks.
This is how the JavaScript Call Stack, Event Loop, Call Back Queue, Microtasks Queue and WEB API Environments work.
Now Run this below code, before running try to guess the outcome. It will be exactly as per what I have written above :
//Synchronous Code - Always prioritized over async code
console.log('Asynchronous TEST start');
//It is a 0 Second Timer, But a timer is not a microtask
setTimeout(() => console.log('0 sec timer'), 0);
//Promise is a microtask
Promise.resolve('Resolved promise 1').then(res => console.log(res));
//2nd promise is a microtask too
Promise.resolve('Resolved promise 2').then(res => {
for (let i = 0; i < 1000000000; i++) {} //very large loop
console.log(res);
});
//Synchronous Code - Always prioritized over async code
console.log('Test end');
SPOILER ALERT for above snippet:
As you can see, the timer runs in the end although it is a 0 second timer, it does not actually execute at 0 seconds. Why is that? Because Settimeout uses a callback, and promises are microtasks, Microtask Priority is always greater than Callback Priority
You are correct up until this point:
That means if we assume it took (say) 10ms to come to the end of the code, then since the event-queue has the setTimeout (i) in the front, it waits for 3s, then pops the alert: "Hello 1", at the time = 3010ms
setTimeout will queue the callback to run after a certain time from the moment the setTimeout is called. For example, if setTimeout(fn, 3000) is run, and then 5 seconds of expensive blocking code runs, fn will run immediately after those 5 seconds. If 1 second of blocking code runs instead, fn will run 2 seconds after that blocking code finishes. For example:
console.log('script start');
// Putting the below in a setTimeout so that the above log gets rendered
setTimeout(() => {
setTimeout(() => {
console.log('setTimeout callback');
}, 1000);
const t0 = Date.now();
while (Date.now() - t0 < 700);
console.log('loop done');
}, 30);
Above, you can see that the for loop takes some time to finish, but once it does, the setTimeout callback runs nearly immediately afterwards.
You can think of it like: when setTimeout is called, at Date.now() + delay, a new task gets pushed to the macrotask queue. Other code may be running at the time the task gets pushed, or it may have taken some time before the code after the setTimeout finished, but regardless, the callback will run as soon as it can after Date.now() + delay.
This process is described precisely in the specification:
(After waiting is finished...) Queue a global task on the timer task source given method context to run task.
The task does not exist in the queue (or in the stack) until the time elapses, and the function call only goes into the stack once the task starts running - which may occur as soon as the time elapses, or it may take some additional time if a different task is running at that time.
we had addEventListener()'s with some call-back functions. Even in this case, will the call-back functions of the event listeners be enqueued in the event-queue?
No - their handlers will only get put into the queue once the listener fires.
So we all know setTimeout waits a certain amount of time before executing something. My question is, does it wait for the above code to finish executing first, before waiting a second to execute something else, or does it just wait for a second, and whether or not the above code has finished executing, it executes the rest of the code anyways?
if (1 == 1) {
//huge chunk of code
} //end of if (1 == 1)
var theTime = 1000;
var timeout = setTimeout("location.reload(true);", theTime);
function resetTimeout() {
clearTimeout(timeout);
timeout = setTimeout("location.reload(true);", theTime);
} //end of function resetTimeout()
My goal is to get the first part of the code to finish executing, then refresh the page as soon as the first part of the code has finished executing. Is there a way to do that?
In your case, the page will reload 1 second after setTimeout was called. So it's the "huge chunk of code" time plus 1 second.
To refresh the page as soon as the first part of the code finishes, just call location.reload without setTimeout:
if (1) {
//huge chunk of code
}
location.reload(true);
EDIT: This approach doesn't wait for asynchronous code to finish. For example, the program below is interrupted by the reload before the alert box pops up.
if (1) {
setTimeout(() => alert('Test'), 1000);
}
location.reload(true);
If you setTimeout to a very small value (e.g. 1ms, possibly even zero, but haven't checked that) it will execute as soon as your main code is finished. It won't execute before your main code is finished, because JavaScript is not multi-threaded.
JavaScript is single-threaded and non-preemptive, it's not possible to interrupt code that's running. Asynchronous code, such as timeouts and AJAX callbacks, cannot run until the currently executing code returns to the main event loop.
The timer in setTimeout starts immediately when it's called. But because of the single-threaded design, the callback can't be called until all your current JS finishes. If that takes longer than the timer, then the callback will be delayed. So all you're guaranteed is that the callback will be called in at least that amount of time -- it might be longer, but not shorter. There could also be other asynchronous callbacks ahead of it in the event queue.
I would like to change the content of a paragraph while the button handler is running rather than waiting for the button handler to finish. Here is my code:
Output: <p id="output"></p><br><br>
<input type="button" onclick="buttonPressed()" value="submit" id="button"><br><br>
<script>
function buttonPressed(){
console.log("output 2")
document.getElementById("output").innerHTML = "output 1"
while (true){
// doing something that takes a long time
}
}
console.log("output 1")
document.getElementById("output").innerHTML = "output 1"
</script>
upon pressing the button I would like the output to read "output 2" rather than having to wait for the button handler to finish. I have a while true in the button handler to demonstrate this, in reality I won't have a while true but rather some kind of process that takes a while. I would like to let the user know that this process has begun and that they should wait for it to finish.
Thanks for the help
The reason that your output is not showing is because the browser thread is busy with executing the current task (your function). As a result, the browser cannot redraw the page which would show the updated output.
In order to get around this, you need to use two separate tasks. One way to accomplish this would be to simply run your long running code in a timeout.
function buttonPressed(){
console.log("output 2")
writeOutput("output 2")
setTimeout(function(){ //use a separate task and allow the page to draw
while (true){
// doing something that takes a long time
}
},4);
}
As a side note, 4 is used here because 4 milliseconds is generally the smallest time you can use for one timeout due to browser limitations and the html5 spec
I am very new to node.js. Am trying to understand what exactly is meant by 'asynchronous' in terms of node js.
In the above context I have the below code:-
function foo()
{
setImmediate(function two()
{
console.log(1);
});
setTimeout(function one()
{
console.log(3);
},0);
process.nextTick(function three()
{
console.log(2);
});
console.log(4);
}
foo();
can some one please explain me, in depth, as to what exactly would be the order of execution for all of the above timer APIs and WHY will it be so? Any explanations/references regarding the call back stack etc. will also be helpful.
First of all, 4 gets logged first because all other calls to setImmediate, setTimeout or nextTick delay the execution of a function to somewhere after the currently executing code. But they all do it differently:
setTimeout
This function allows you to do something after a specific amout of milliseconds. If the milliseconds you pass to this function are less that 1ms, it will always wait 1ms before calling your function.
setImmediate
This function allows you to do something after node has processed all i/o events. Node processes i/o events in every cycle of the event queue. So setTimeout will always execute your function in the next cycle of the event queue. This allows the queue spin unblocked.
process.nextTick
This function allows you to do something immediately after the currently running code finishes. You can imagine it like you would be able to modify the currently executing code and add some lines after it, so that it does something more before it's finished. Calling this function again and again does block the event loop because it cannot go on to the next task in the queue, since it's still busy with the current one. This means, node does not process the i/o events until the last function you passed to nextTick got executed. Therefore you should never call this function recursively or use it too much, because it can stop the event loop from spinning. Node will display a warning if this happens, though.
So.. to explain the output of 4 2 1 3:
4 is the first log that's not getting delayed and thus is the first output.
2 is getting logged immediately after foo() finishes and thus is the second
3 is faster than 1 because a usual event loop cycle is much faster than 1 millisecond, and so.. 3 is the third log
setTimeout delays by at least 1ms which is the longest delay of all the delay functions. It's clearly the last.
Im trying to implement a simple blckjack game, the problem is that the timeOut function is not working as I expect. I wrote some debugging messages to help you understand what I mean. With two words what I see is that the function is called once and than for some reason it exits from the function, program continues executing itself and than retunrs to the timeOut function...
What I want is to pause the program execution to wait user to choose whether to request new card ot to stop.
Thank you in advance!
Where is the waitForUserInput() method being called? Also, why use a timeout for grabbing user input? Why not simply subscribe to the mouse click event?
setTimeout will not stop exection of a script. It is just for delayed execution. After you call it - execution of program will be continued as usual, but after specified time - function passed as a first parameter will be executed. To wait for user input - take a look at click/keyup/keydown etc. events.
You should not do things like below in JS. JS always single thread and such loops will just freeze your interface. In yor case it looks like you should place onclick event on card block and put there a code which will do what you need.
while(true){
waitForUserInput();
if(requestCard){
userHand.hitMe();
var userHandCards = userHand.printHand().split(",");
displayCard(userHandCards[cardIndex]);
cardIndex++;
//console.log(">"+userHand.score());
if(userHand.score()>21){
break;
}
}else{
break
}
};
What I want is to pause the program execution to wait user to choose whether to request new card ot to stop
You should place some buttons with onclick handlers specified. And just run code you need depending on clicked button. Right now I do not see how user can say to your program about his choice. If that is a keybord command ("s" pressed than stop, "n" - next card ) - you can try to use document.onkeyup.