Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding JavaScript's single-threaded nature

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?

like image 381
wmock Avatar asked Jan 29 '14 21:01

wmock


People also ask

What is single threaded nature?

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.

What does it mean to be single threaded?

"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.

How does single threaded Async work?

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.

What does it mean that Redis is single threaded?

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.


2 Answers

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/

like image 198
jfriend00 Avatar answered Sep 19 '22 19:09

jfriend00


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).

like image 30
samanime Avatar answered Sep 20 '22 19:09

samanime