I was in an awkward situation,
I am working with pure JavaScript for almost 3 years, and I know that JavaScript is single-threaded language,
and that you can simulate asynchronous execution using setInterval and setTimeout functions,
but when I thought about how they can work I couldn't clearly understand it.
So how these functions affect execution context?
I suppose that in specific time runs only one part of the code and after it switches to
another part. If so, then would a lot of setInterval or setTimeout
calls affect performance?
Javascript is singled-threaded but the browser is not. The browser has at least three threads: Javascript engine thread, UI thread, and timing thread, where the timing of setTimeout and setInterval are done by the timing thread.
When calling setTimeout or setInterval, a timer thread in the browser starts counting down and when time up puts the callback function in javascript thread's execution stack. The callback function is not executed before other functions above it in the stack finishes. So if there are other time-consuming functions being executed when time up, the callback of setTimeout will not finish in time.
How setTimeout / setInterval work's in JavaScript
Browser has API for Timer function just like API for event ex.
'click'
'scroll'
Assume that you have following code in your application
function listener(){
...
}
setTimeout(listener, 300)
function foo(){
for(var i = 0; i < 10000; i++){
console.log(i)
}
}
foo()
![See How Function Execution work's in javascript ][1]
[1]: https://i.stack.imgur.com/j6M6b.png
At this point as per our code we wrote above our call stack will look like
Call Stack -> foo
And let's assume that foo will take 1s to complete it's execution, as we already defined 1 timeout in our code and we are running it before "foo" complete's it's execution i.e at 300ms
What will happen then ?
Does javascript stop executing foo and start executing setTimeout ?
No
As we already know javascript is single threaded so it has to complete execution of foo before moving ahead, but how does browser ensure that after execution of foo the "setTimeout" will execute ?
Here javascript magic comes into picture
When 300ms is expired, the browser's "Timer API" kicks in and put the timeout handler into "Message Queue".
At this point "Message Queue" in above image will look like
Message Queue -> setTimout:listner
And
Call Stack -> foo
And when "Call Stack" becomes empty i.e foo completes it's execution the "Event Loop" as shown in the image will take the message from message queue and push it into stack
The only job of "Event Loop" is when "Call Stack" becomes empty and "Message Queue" has entry in it then dequeue the message form "Message Queue" and push it into "Call Stack"
At this point Message Queue in above image will look like
Message Queue ->
And
Call Stack -> listener
And that's how setTimeout and setInterval works, even though we specify 300 ms in the setTimeout it will execute after "foo" completes it's execution in this case i.e after 1s.
And that's why timer specified in setTimeout/setInterval indicates "Minimum Time" delay for execution of function.
Javascript is single threaded but browser is not.
There is 1 stack where function and statements get executed.
there is 1 queue where function are queued to be executed.
there are web APIs which can hold the function for particular time, defined in setTimeout and setInterval in event table.
when javascript engine execute js file line by line, if it finds a line as statement or function call it load it on stack and execute but if it is setTimeout or setInterval call,
then function handler associated with setTimeout or setInterval is taken out by TIME API (one of web API of browser)and hold it for that time.
Once this time is over, Time Api put that function at end of execution queue.
Now Execution of that function depends on other functions calls which are ahead of in queue.
Note: this function call is called upon window object.
setTimeout(function () {console.log(this)}, 300)
Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
JavaScript is a single-threaded scripting language, so it can execute one piece of code at a time (due to its single-threaded nature) each of these blocks of code is “blocking” the progress of other asynchronous events. This means that when an asynchronous event occurs (like a mouse click, a timer firing, or an XMLHttpRequest completing) it gets queued up to be executed later.
setTimeout()
when you use setTimeout() it will execute only when its turn comes in a queue, if an earlier event (of setTimeout) blocks due to some reason setTimeout can be delayed than the specified time in setTimeout() function. during the execution of setTimeout callback function, if any event occurs(e.g click event),it gets queued up to be executed later.
setTimeout(function(){
/* Some long block of code... */
setTimeout(arguments.callee, 10);
}, 10);
setInterval(function(){
/* Some long block of code... */
}, 10);
setInterval()
Similar to setTimeout but continually calls the function (with a
delay every time) until it is canceled.
setTimeout code will always have at least a 10ms delay after the
previous callback execution (it may end up being more, but never
less) whereas the setInterval will attempt to execute a callback
every 10ms regardless of when the last callback was executed.
If a timer is blocked from immediately executing it will be delayed
until the next possible point of execution (which will be longer than
the desired delay). Intervals may execute back-to-back with no delay
if they take long enough to execute (longer than the specified
delay).
Just a note in regards to my experience, If you are going to use setTimeout(), the function will always be delayed (and I mean executed later) or executed after further code which is not 'timeouted'. This may happen even with functions which have delay = 0 and is caused by Event Loop.
See example below:
setTimeout(function() {
console.log('Second');
}, 0)
console.log('First');
I am new to Javascript and Asynchronous programming, a few things confuse me.
Consider the following code
function fun(callback) {
console.log('a');
setTimeout(callback,0);
console.log('c');
}
fun(() => {console.log('b');});
I know that the callback of setTimeout function is put inside Event queue and rest are put inside call stack, tasks in event queue are executed only when call stack is empty, but I know that is not the case for all callbacks.
What makes functions like setTimeout special ?
If there are any misfacts in my understandings please point it out.
You know almost all, If we use setTimeout example like this : setTimeout(func, 0), This ensures that the func is scheduled as soon as possible. But the timer does this only when the current code operation is finished. Therefore, the timer starts running "right after" the current job. In other words, "asynchronous". For example, the code below prints "Hello" followed by "World".
setTimeout(() => alert("World"), 0);
alert("Hello");
In the first line it means "queue the call after 0ms".But the timer looks after "check queue first" ie after running the current code.From this "Hello" is written before "World" after.I hope I could explain. Happy coding!!!
I wanted to have a better understanding of how the event loop and asynchronous code works in Javascript. There is a ton of resources online but I could not find an answer to my question
Everyday I mostly use callbacks, promises, async/awaits, but at the end I am simply relying on already asynchronous methods.
Therefore I wanted to know how it works, creating an async function from scratch, and deal with blocking code (or should I say slow code, that is not an HttpRequest or anything that is already provided to us).
For example taking while loop with a very high condition to stop it, should take a second to finish. And this is what I decided to implement for my tests.
After my research, I could read that one way of making my code asynchronous, would be to use setTimeout with a 0ms delay (placing a message in the event queue, that will be executed after the next tick)
function longOperation(cb) {
setTimeout(function() {
var i = 0;
while (i != 1000000000) { i++; }
cb();
}, 0);
}
longOperation(() => {
console.log('callback finished');
})
console.log('start');
My question is:
When my code is finally going to be executed, why isn't it blocking anymore ? What is the difference between executing it normally, and placing a message that the event loop will pick to push it to the call stack ?
The following video shows how the event loop handles a setTimeout with 0 delay.
JavaScript Event loop with setTimeout 0
However, the code executed is a simple console log. In my example, this is a "long" operation...
The outer code executes to completion.
The setTimeout 0 timer expires immediately, so its callback runs right away and executes to completion (the long-running while loop and its callback).
During both of these code execution phases, no other JavaScript user code will run.
In Javascript, I have two versions of a recursive function, one that runs synchronously and one that uses simple scheduling to run asynchronously. Given certain inputs, in both cases the function is expected to have an infinite execution path. I need to develop tests for these functions, specifically a test to check that the asynchronous version does not block the main thread.
I already have tests that check the output callback behavior of these functions in non-returning cases, I am only concerned about testing the blocking behavior. I can limit how long the function runs to some long but finite amount of time for testing purposes as well. I am currently using QUnit but can switch to another testing framework.
How can I test that a non-returning, asynchronous function does not block?
Edit, For Clarification
This would be a bare bones example of the function I am working with:
function a()
{
console.log("invoked");
setTimeout(a, 1000);
}
a();
I am intentionally misusing some threading terms in my description because I felt they most clearly expressed the problem. By not blocking the main thread, I mean that invoking the function does not prevent the scheduling and execution of other logic. I expect the function itself will be executed on the main thread but I consider the function running as long as it is scheduled for execution in the future.
Unit Test are based on single-responsability-principle and isolation (separate the subject under test from it's dependencies).
In this case, you expect your function to run asynchronously but this behaviour is not done by your function, is done by the "setTimeout" function, so I think you must isolate your function from "setTimeout" since it's a dependency you don't want to test, the browser guarantees you it will work.
Then, as we trust "setTimeout" will do the asyncrhonous logic, we can only test our function calls to "setTimeout" and we can do this replacing "window.setTimeout" with another function while we must always restore it after the test is complete.
function replaceSetTimeout() {
var originalSetTimeout = window.setTimeout;
var callCount = 0;
window.setTimeout = function() {
callCount++;
};
window.setTimeout.restore = function() {
window.setTimeout = originalSetTimeout;
};
window.setTimeout.getCallCount = function() {
return callCount;
};
}
replaceSetTimeout();
asyncFunction();
assert(setTimeout.getCallCount() === 1);
setTimeout.restore();
I recommend you to use sinon.js as it provides many tools like spies who are functions than will inform you about how many times and with what arguments where called.
var originalSetTimeout = window.setTimeout;
window.setTimeout = sinon.spy();
asyncFunction();
// check called only once
assert(setTimeout.calledOnce);
// check the first argument was asyncFunction
assert(setTimeout.calledWith(asyncFunction));
Sinon also provides fake timers who does the setTimeout substitution but with so much more features, like the .tick(x) method who will simulate "x" milliseconds but in this case I think it doesn't help you.
Update to answer question edit:
1 - Your function executes infinitely so you cannot test it without interrupting it's execution, so you must overwrite "setTimeout" somewhere.
2 - You want your function to execute recursively allowing other code to be executed between iterations? great! but understand than your function can not do this your function only can call setTimeout or setInterval and hope this function work as expected. You should test what your function does.
3 - You want to test from Javascript (a sandboxed environment) than another Javascript code uses and releases the only one execution thread (the same you are using to test). Do you really think this is an easy test?
4 - but the most important one - I don't like white box because it couples the test with the dependency, if you change your dependency or how it's called in the future you will have to change the test. This problem doesn't exist with DOM function, DOM functions will keep the same interface for years, and for now, you have no other way to do what you want than calling one of those two functions, so I don't think in this case "white box testing" is a bad idea.
I told you this because I had the same problem testing a Promise pattern implementation than had to be always asynchronous, even if the promise is already fulfilled, and I've tested it using test-engine asynchronous-test way (using callbacks and stuff) and it was a mess, test failing randomly, so much slow test execution. Then I asked a TDD expert how can test be so hard and he answered than I was not following Single Responsability Principle since I was trying to test my promise implementation AND the setTimeout behaviour.
If you think about it from a Behaviour Driven Testing perspective then 'Does my function block?' is not a useful question. It will definitely block, a better question might be 'does it return in no more than 50ms'.
You could do this with something like :
test( "speed test", function() {
var start = new Date();
a();
ok(new Date() - start < 50, "Passed!" );
});
The issue with this is that if someone does do something silly that makes your function block indefinitely the test won't fail, it will hang.
Because JavaScript is single threaded there is no way around this. If I come along and change your function to :
function a() {
while(true) {
console.log("invoked")
}
}
The test will hang.
You can make breaking things this way harder by refactoring things a little. There are 2 separate things being done. Your chunk of work and the scheduling. Separate these and you'll end up with something like the following functions :
function a() {
// doWork
var stopRunning = true;
return stopRunning;
}
function doAsync(workFunc, scheduleFunc, timeout) {
if (!workFunc()) {
scheduleFunc(doAsync, [workFunc, scheduleFunc, timeout], timeout);
}
}
function schedule(func, args, timeout) {
setTimeout(function() {func.apply(window, args);}, timeout);
}
Now you're free to test everything in isolation. You can supply a mock workFunc and scheduleFunc to a test for doAsync to verify it behaves as expected and you can test your function a() without worrying about how it is scheduled.
It's still possible for a dunce programmer to put an infinite loop into the function a(), but because they don't have to consider how to run further units of work it should be less likely.
To test or prove an infinitely executing execution path will never block is next to impossible, so you have to split your problem up into parts.
Your path is basically foo(foo(foo(foo(...etc...)))), nevermind that SetTimeout actually removes recursion. So all you have to do is test or prove that your foo does not block (I tell you now that testing will be "a bit" easier than proving, more below)
So, does function foo block?
Talking a bit maths, if you want to know whether f(f(...f(x)...)) always has a value, you actually only have to prove that f(x) always has a value for any x that f can return. It does not matter how many recursions you have, if you can make sure their return values are fine.
What that means for your foo is that you only have to prove that foo does not block for any possible input value. Keep in mind that in this case, all global variables and closures are input values too. This means you have to sanity-check every single value you are using on every call.
To test, of course you will have to replace SetTimeout, but that is trivial, and if you replace it with an empty function (function(){}) it is easy to prove that this function does not block or otherwise alter your execution. You will then
Making things easier
Taking in what I wrote above, this also means that you would have to make sure no global function or variable that you are ever using will ever be changed to a point that your function breaks to a point it breaks. This actually is quite hard, but you can still make things easier for you by making sure you always use the same functions and values and that other functions can not touch them by using closures.
function foo(n, setTimeout)
{
var x = global_var;
// sanity check n here
function f()
{
setTimeout(f, n)
}
return f();
}
This way, you only have to test those values on the first execution. It's nice to be able to assume Math.Pi is actually Pi and not a string value containing "noodles". Really nice.
Do not use global mutable objects
Call those you can not circumvent using setTimeout to ensure they can not block
If you need return values, things will get really tricky, but possible, consider this:
function() {
var x = 0;
setTimeout(function(){x = insecure();}, 1);
}
All you have to do is
Use x next iteration
Sanity check value of x first!
Does SetTimeout block?
Of course this depends on whether setTimeout blocks. This is quite hard to prove, but a bit easier to test. You can't actually prove it since it's implementation is up to the interpreter.
Personally I would assume that setTimeout behaves like an empty function when it's return value is discarded.
Performing this asynchronous testing is actually possible in QUnit but is handled better in another JavaScript testing framework, Jasmine JS. I'll provide examples in both.
In QUnit you need to first call the stop() function to signal that the test is expected to run asynchronously, you should then call setTimeout with a function that includes your expectations as well as a call to the start() function to complete the block. Here's an example:
test( "a test", function() {
stop();
asyncOp();
setTimeout(function() {
equals( asyncOp.result, "someExpectedValue" );
start();
}, 150 );
});
Edit: Apparently there's also a whole asyncTest construct that you can use that simplifies this process. Take a look: http://api.qunitjs.com/asyncTest/
In Jasmine (http://pivotal.github.com/jasmine/), a Behavior Driven Development (BDD) testing framework, there are built-in methods for writing asynchronous tests. Here's an example of an asynchronous test in Jasmine:
describe('Some module', function() {
it('should run asynchronously', function() {
var isDone = false;
runs(function() {
// The first call to runs should trigger some async operation
// that has a side-effect that can be tested for. In this case,
// lets say that the doSomethingAsyncWithCallback function
// does something asynchronously and then calls the passed callback
doSomethingAsyncWithCallback(function() { isDone = true; });
});
waitsFor(function() {
// The call to waits for is a polling function that will get called
// periodically until either a condition is met (the function should return
// a boolean testing for this condition) or the timeout expires.
// The optional text is what error to display if the test fails.
return isDone === true;
}, "Should set isDone to true", 500);
runs(function() {
// The second call to runs should contain any assertions you need to make
// after the async call is complete.
expect(isDone).toBe(true);
});
});
});
Edit: Also, Jasmine has several built-in methods of faking out the setTimeout and setInterval functions of the browser without hosing any other tests in your suite that may depend on that. I would take a look at using those rather than manually overriding the setTimeout/setInterval functions.
Basically, JavaScript is single-threaded, so it will block the main thread. But :
I assume you're using setTimesout to schedule your function, so it won't be noticeable to the user if calls to that function don't take too much time (say, less than 200 or 300ms).
If you're doing DOM manipulation during that function (including Canvas or WebGL), then you're screwed. But if not, you can look into Web Workers, which can spawn separate threads that are guaranteed not to block the UI.
But anyway, JavaScript and the main loop, that's a tricky issue that's been bugging me a lot these past months, so you're not alone!
As soon as your function returns (after having set the timeout for it's next run), javascript will look at the next thing that requires running and run that.
As far as I can tell, the 'main thread' in javascript is just a loop that is responding to events (such as onload for a script tag, which runs the contents of that tag).
Based on the above two conditions, the calling thread is always going to run to completion despite any setTimeouts, and those timeouts will begin after the calling thread has nothing left to run.
The way I tested this was to run the following function right after the call to a()
function looper(name,duration) {
var start = (new Date()).getTime();
var elapsed = 0;
while (elapsed < duration) {
elapsed = (new Date()).getTime() - start;
console.log(name + ": " + elapsed);
}
}
Duration should be set to some period of time longer than the setTimeout duration in a(). The expected output would be the output of 'looper', followed by the output of repeated calls to a().
The next thing to test would be whether other script tags are able to run while a() and its child calls are executing.
You can do this like so:
<script>
a();
</script>
<script>
looper('delay',500); // ie; less than the 1000 timeout in a();
</script>
<script>
console.log('OK');
</script>
You would expect 'OK' to appear in the log despite the fact that a() and its children are still executing. You can also test variations of this, such as window.onload(), etc.
Finally, you'd want to ensure that other timer events work fine as well. Simply delaying 2 calls by half a second and checking that they interleave should show that works fine:
function b()
{
console.log("invoked b")
setTimeout(b, 1000);
}
a();
looper('wait',500);
b();
Should produce output like
invoked
invoked b
invoked
invoked b
invoked
invoked b
Hope that's what you were looking for!
EDIT in case you need some technical details on how to do it in Qunit:
If Qunit can't capture console.log output (i'm not sure), just push those strings into an array or a string and check that after it's run. You could override console.log in the test module() setup and restore it at teardown. I'm not sure how Qunit works but 'this' might have to be removed and globals used to store the old_console_log and test_output
// in the setup
this.old_console_log = console.log;
this.test_output = [];
var self = this;
console.log = function(text) { self.test_output.push(text); }
// in the teardown
console.log = this.old_console_log;
Finally, you can utilize stop() and start() so that Qunit knows to wait for all the events in the test to finish running.
stop();
kickoff_async_test();
setTimeout(function(){
// assertions
start();
},<expected duration of run>);
Based on all the answers, I came up with this solution that works for my case:
testAsync("Doesn't hang", function(){
expect(1);
var ranToLong = false;
var last = new Date();
var sched = setInterval(function(){
var now = new Date();
ranToLong = ranToLong || (now - last) >= 50;
last = now;
}, 0);
// In this case, asyncRecursiveFunction runs for a long time and
// returns a single value in callback
asyncRecursiveFunction(function callback(v){
clearInterval(sched);
var now = new Date();
ranToLong = ranToLong || (now - last) >= 50;
assert.equal(ranToLong, false);
start();
});
});
It tests that 'asyncRecursiveFunction' does not hang while processing by looking at the time between another scheduled function calls.
This is really ugly and not be applicable to every case but it seems to work for me because I can restrict my function to some large set of async recursive calls so it runs for a long but not infinite time. As I mentioned in the question, I am happy proving that such cases do not block.
BTW, the actual code in question is found in gen.js. The main problem was an async reduce generator. It correctly returned a value asynchronously, but in previous versions would stall because of synchronous internal implementation.
The following code is taken from Project Silk (a Microsoft sample application)
The publish method below loops thru an an array of event callBacks and executes each one. Instead of using a for loop setInterval is used instead.
The documentation says this allows each subscriber callback to be invoked before the previous callback finishes. Is this correct? I thought the browser would not allow the execution of the function inside the interval to run until all prior executions of it had finished.
Is this really any different than doing a for loop?
that.publish = function (eventName, data)
{
var context, intervalId, idx = 0;
if (queue[eventName])
{
intervalId = setInterval(function ()
{
if (queue[eventName][idx])
{
context = queue[eventName][idx].context || this;
queue[eventName][idx].callback.call(context, data);
idx += 1;
}
else { clearInterval(intervalId); }
}, 0);
}
Using setInterval here does make the execution sort of "asynchronous", because it schedules the execution of the callback for the next time the main execution thread is available.
This means that the callback executions should not block the browser because any other synchronous processing will take place before the callbacks (because the callbacks are scheduled to run only when the main execution thread has a spare millisecond) - and that's what makes this construct "better" than a regular for loop - the fact that the callbacks won't block the browser and cause the dreaded "This page has a script that's taking too long" error.
The side effect of this scheduling pattern is that the timeout is only a "suggestion" - which is why they use 0 here.
See: http://ejohn.org/blog/how-javascript-timers-work/
setInterval(..., 0) can be used to yield control to the browser UI, to prevent it from freezing if your code takes a long time to run.
In this case, that.publish will exit almost immediately before any callback has been executed. Each callback will then run "in the background" - they will be placed in the event loop, and each one will yield to the browser to do it's thing before the next callback is executed.
This seems like a good idea in event processing, because you don't want event processing to freeze the browser even if there are a lot of them or some take a long time to finish.
About the documentation - as stated, it is incorrect. Javascript is single-threaded. But if you were to call publish() a few times in a row, it is true that those calls would all finish before any callbacks are executed, because of the setTimeout. Maybe this is what the documentation means?