I've been reading John Resig's "Secrets of a JavaScript Ninja" and it explains that JavaScript is single-threaded. However, I tried testing this and I'm not sure what to take away from here:
// executing this in browser
(function () {
// throw something into event queue
setTimeout(function () {
alert("This will be called back after 1 second.");
}, 1000);
// arbitrary loop to take up some time
for (var i = 0; i < 10000; i += 1) {
console.log(i);
}
})();
Maybe I'm not understanding exactly what being single-threaded means, but I thought that the setTimeout callback wouldn't execute until all of the outer anonymous function is complete. However, running this in the browser shows that the callback function gets called while i's are still being outputted onto the console. To me, this seems like there's 2 threads with anonymous function's invokation occupying 1 thread and then the callback using the 2nd thread.
Can someone help un-confuse me?
Single threaded means it has only one call stack. Whatever is on the top of the call stack is run first. In the above program, functions are run sequentially.
"Single-threaded" means that we open a single connection and measure the speeds from that. "Multi-threaded" means that we're using multiple connections - usually anywhere from 3 to 8 - at the same time, and measure the total speed across them all.
Another example with a single-thread approach is a program that requests a file from the OS and needs to make a mathematical operation. In an asynchronous system, the program asks the OS for the file and returns the control to the mathematical operation to be executed on the CPU, while waiting for the file.
Redis is *kinda* single threaded, since there are threads in order to perform certain slow operations on disk. So far threaded operations were so focused on I/O that our small library to perform asynchronous tasks on a different thread was called bio. c: Background I/O, basically.
console.log()
is a weird function in some browsers (like Chrome) and is not synchronous itself so you can't really use it to gauge the single threadedness. What you are probably seeing is that the JS engine executes all the console.log()
statements and then the setTimeout()
runs to show the alert and, in parallel (in some other process that isn't javascript) all the data is being shown in the console.
Javascript is indeed single threaded. In your example, the setTimeout()
callback will not execute until your for
loop is done.
You can illustrate it better like this:
(function () {
// throw something into event queue
setTimeout(function () {
alert("This will be called back after 1 second.");
}, 1000);
function now() {
return new Date().getTime();
}
var start = now();
// loop for 1.2 seconds
while (now() - start < 1200) {}
alert("Looping done");
})();
Working jsFiddle demo: http://jsfiddle.net/jfriend00/3sBTb/
This is a bit of a tricky concept to understand. Throwing in things like event listeners also further muddies up the picture.
A simple way to think of it is as if you have a conveyor belt. You have your normal function calls all evenly spaced out, with room in between.
Things that are asynchronous things (timeouts, triggered events, etc.) fill those spots. There isn't an infinite amount of room between each of those normal calls, so it fits what it can from this queue, does a little more of the normal synchronized functions, fills some more space with asynchronous, etc.
The affect appears to be somewhat multi-threaded (and indeed you can cause race conditions of a sort with asynchronous calls). In many cases, the distinction doesn't matter. However, it is important to remember this.
However, when you try to debug things, especially when using tools like Chrome's console.log
, it can look like things are scrambled because console.log itself is asynchronous (if it were synchronous, it would freeze your script on a long function).
You can see this yourself if you output something like this:
var input = document.createElement('input');
input.setAttribute('value', 0);
function inc() {
input.setAttribute('value', parseInt(input.getAttribute('value'))+1);
console.log(input);
if (parseInt(input.getAttribute('value')) < 100) {
setTimeout(inc, 10);
}
}
inc();
JSFiddle: http://jsfiddle.net/c2PnP/
What this script does it creates an input element, then every 10 milliseconds, it increments the value of input, then outputs the input element. It repeats 100 times (until value = 100).
If you look at your console, you'll notice that some of the values will be duplicated, it won't be a smooth progression. For example, on a run I just did, I see 5 inputs with a value of "100" and gaps for the missing numbers. This is because console.log is running asynchronously and only outputting when it gets the gap to do so.
(Note: If you have a super fast computer, you may need to decrease the time to something smaller, like 1, and/or increase the number of iterations to a bigger number).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With