4

Consider the following piece of code:

var some_expensive_task = function(i) {
    setTimeout(function() {
        var a = 1;

        while (a < 100000000) {
            Math.sqrt(a);

            ++a;
        }
        console.log('finished set' + i);
    }, 0);
};

for (var i = 0; i < 70; ++i) {
    console.log('start ' + i);
    some_expensive_task(i);
    console.log('end ' + i);
}

The intent of this program was to iterate over and start 70 cpu intensive asynchronous tasks using setTimeout.

As expected, the output of this program is:

start 1
end 1
...
start 69
end 69
finished set1
...
finished set69

Throughtout the entire execution, there were only two processes. One of which I assume was the idle event loop and the other was the worker process running at 100%.

Am I correct in understanding that while the event loop is executed synchronously, asynchronous tasks that are started, regardless of origin, are executed synchronously in the order that they were called?

UPDATE

I still don't feel as if I've conveyed my question clear enough. Using setTimeout was the only way I could think of to accurately schedule a bunch of async functions to run. I guess the real question is, if I start three async functions with setTimeout, still with a zero delay, is the second one I start guaranteed to run after the first one finishes and is the third one guaranteed to start after the second one finishes?

brian
  • 2,745
  • 2
  • 17
  • 33
  • 1
    I think you need to make a distinction between the asynchronous task (wait for 0 ms) and the callback (cpu intensive synchronous loop) – Bergi Aug 20 '14 at 10:10
  • @Bergi, I suppose the task in this case was just meant to provide a sort of in-function delay to illustrate the order in which things are executed. – brian Aug 20 '14 at 21:16
  • You probably want to take a look at the `child_process` module at http://nodejs.org/api/child_process.html if you want multithreading. – david Aug 22 '14 at 02:24

4 Answers4

3

You use incorrect terminology in the question, Are Node.js asynchronous tasks handled synchronously does not make much sense. And the test case is not what you think it is. First making clear some terminologies:

Synchronous functions are guaranteed to run/complete in the order of their invocation.

Asynchronous functions can progress and complete out-of-order w.r.to their calling.

Blocking operations are those operations which once started must complete for the execution to progress further. CPU-intensive operations are blocking unless you run them on a separate worker. loops are blocking in nature. Once they start, they will complete all iterations before next function is executed.

setTimeout simply calls the passed function at least x ms after current time. Calling it means once x ms pass it queues the passed function on the event loop. It is just delayed execution.

So considering above facts, here is why your test is misleading:

  • First your test case (your CPU-intensive function) is not asynchronous, you wrapped it around a setTimeout which is asynchronous. The timeout of 0 simply implies that they will be executed in the same order they are called. All callback functions being synchronous.

  • Second, start and end in the log indicates point where your setTimeout is called. This would be in-order as expected. With timeout 0, the completion will be in-order too. Yes if you keep timeout equal for them they all will be executed in the same order as passed. Then again this is one of many possible cases where outcome is similar to synchronous (what if timeouts were in increasing order?). What you asked may be true for these cases but not always.

  • Third if you wanted to simulate asynchronicity (enough to see out-of-order behaviour on console), might as well loose the while loop and use random timeouts(Math.random()*1000). You will see they complete in arbitrary fashion. This would be asynchronous execution (of setTimeout not the callback).

user568109
  • 47,225
  • 17
  • 99
  • 123
  • `Asynchronous functions can progress and complete out-of-order w.r.to their calling.` I don't understand this sentence. Functions are always synchronous from the entry point to the exit point. They may schedule tasks to be called later but it doesn't mean that they do anything out-of-order. At least this is not a formal definition. There is no such thing as asynchronous functions to be formal. And thus there is no such thing as synchronous functions. There are only functions. – freakish Aug 20 '14 at 14:55
  • To elaborate a bit more: is this function `var L = []; function T(x) { L.push(x); }` synchronous or asynchronous? – freakish Aug 20 '14 at 16:10
  • @freakish: There are no "asynchronous functions" in javascript, that's right. All functions run synchronously until they return to their caller. However, the *environment* gives us some functions that take a callback function, start an asynchronous task and schedule the callback for when that is finished, and return immediately. `setTimeout` is such an environment function: it synchronously, immediately returns a timer id, and internally schedules the callback to be invoked in any order in the future. Of course, the execution of that javascript function runs synchronously then. – Bergi Aug 20 '14 at 16:35
  • @user568109: `setTimeout` is always asynchronous, even if you pass a timeout of 0 ms. It never runs the callback before it returns. – Bergi Aug 20 '14 at 16:36
  • Maybe the correct question is: do asynchronous tasks block other asynchronous tasks? – brian Aug 20 '14 at 21:22
  • @freakish Functions which are asynchronous defer the execution to environment like queue it to the next cycle/wait for IO but do return some value when executed akin to synchronous functions. User may feel function has finished but effect of its operations may be pending. Say, A()B() are executed then they will be finished in the same order as called if they were synchronous. Your example is synchronous, if you call it multiple times you can tell the output as it is deterministic. – user568109 Aug 21 '14 at 00:38
  • @Bergi Right. But the example was misconstrued. You cannot say if function is asynchronous or not from looking at the console. eBrian seemed to have been thinking they execute synchronously. The point of using different timeouts was just to show the opposite. – user568109 Aug 21 '14 at 00:47
  • @user568109 The example I've given is essentially what `setTimeout` does. If you say that it is synchronous, then you have to admit that `setTimeout` is synchronous as well. And I totally agree with that. My point is that the concept of (a)synchronous functions just can't be defined well. Thus we should only talk about functions and task scheduling. – freakish Aug 21 '14 at 07:48
  • @freakish There is no formal definition so it's difficult to converge on one. But since it is JavaScript and there was AJAX before node.js. Many would say it's based on the same idea. Functions with callback executed at end are considered async. In that sense setTimeout is async. The async concept only applies to a higher level. There is a lower event-loop system which node.js utilizes for async behaviour. – user568109 Aug 21 '14 at 08:23
  • @user568109 First of all: I know how event loop works. Secondly: AJAX is not a function. Thirdly: not all functions with callbacks are "asynchronous", e.g. `.forEach` method of lists. Fourthly: now you say that async applies only to a higher level? I see where it goes: next time you will just give us a list of asynchronous functions. :) Just admit that this wrong. And finally: yep, the usage of "async" word is incorrect in many cases and unfortunately it is very popular nowadays. But we should fight with bad practices. – freakish Aug 21 '14 at 08:28
  • @freakish I know AJAX is not a function. Async term comes from there -Asynchronous JavaScript And XML. Passing functions are omnipresent in JavaScript. Async functions utilize callback, I never said all callbacks are async. This is what you naively assumed. If you want a list of async functions, you can go through the node.js docs, you will find plenty of [references](http://nodejs.org/api/fs.html). If it has been used incorrectly perhaps you should explain what the appropriate meaning is else no one can tell why it's wrong. – user568109 Aug 21 '14 at 09:57
  • @user568109 `Functions with callback executed at end are considered async. In that sense setTimeout is async.` So in that sense `.forEach` is async. That's not my "naive" assumption, it might be your "naive" statement though. But it's sad that you write things you don't think. Also I'm not going to give the appropriate meaning because there is none. I thought I already explained that. The only possible way to define async functions is by listing them. Which then means that you can't create your own async functions. And thus such definition has little value. – freakish Aug 21 '14 at 11:17
  • @freakish Unless you're talking about something else, in Array.forEach the callback is executed for every element as in an iteration not at the end of the foreach itself. You can create your own async functions from eventemitter, which like I said before uses an event loop to run on. I explained best I could have. Won't argue with you now. – user568109 Aug 21 '14 at 12:00
  • @user568109 That's complete nonsense: `function T(f) { f(); }`. Function `T` fires callback at the end, so it is async by your definition. Also `function T(f) { for (var i=1; i<100; i++) setTimeout(f, i); }` is not async because it fires callbacks in a loop (I can even nest them to ensure that they fire one after another, just like `.forEach`). Amusing. You don't seem to understand a word I say. Don't tell me what I can do. Tell me the definition of async function that makes sense. If it is "by listing", then obviously eventemitter does not create async functions. – freakish Aug 21 '14 at 12:14
  • @user568109 Not to mention that eventemitter has **nothing** to do with (a)sync functions since event handlers can be triggered in synchronous and asynchronous ways. You are very confused, my friend. – freakish Aug 21 '14 at 12:21
  • @freakish Use it along with the ordered property of execution, I mentioned before. If one can guarantee A()B() has no out of order execution then its synchronous. I never defined them at one place, if at all there is a definition. I never said there is a predefined list of async functions. That is a list of functions which are asynchronous and internally use eventemitters. – user568109 Aug 21 '14 at 13:13
  • @user568109 Please stop talking about eventemitters: that's completely unrelated. And please read my comment one more time: I can **nest** calls to `setTimeout` (technically just use recursive calls to `T`) so that callbacks will be guaranteed to be executed in order. Let me make you a believer: `function T(f, i) { setTimeout(function() { f(); if (i) { T(f, --i); } }, 0); }`. – freakish Aug 21 '14 at 13:19
  • @freakish which is what you and the OP are saying, a single case of orderliness does not demonstrate async behaviour overall. Put different parameters for timeouts then what happens - `setTimeout(A,300); setTimeout(B,200);`. Fixing parameters will not give all possible scenario. – user568109 Aug 21 '14 at 13:24
  • @user568109 Wow, you really are avoiding the main topic like a pro. What is **async behaviour and/or function**? The only thing I've demonstrated is that all definitons you've given are not useful at all. Try again or admit that there is no such definition and that you are confusing people with this terminology. And don't tell me about changing internal parameters. Different code == different function. You can't force my `T` function to fire callbacks out of order without changing the code. Besides what if I used `process.nextTick` instead of `setTimeout`? What parameter you would change now? – freakish Aug 21 '14 at 13:38
  • @freakish I meant synchronous. What do you say to my last example. setTimeout is not ordered there. – user568109 Aug 21 '14 at 13:39
  • @user568109 It is ordered: `B` will fire before `A`. But I don't see how this is related to things I've written. Let me show you your way of thinking. You said "cows are animals with four legs" and then you gave an example of a real cow. And I gave you an example of a real cat which is a completely different animal (but with four legs) and that your definition of cow is not useful. And as a counter argument you say "yeah, but real cows are cows in my definition". Well, yeah, but how does it make the definition better? – freakish Aug 21 '14 at 13:43
  • @freakish That is with respect to the order of their calls. That really is no analogy there. You keep clinging to definitions. You know there isn't one for JavaScript so you keep asking for one. The best I can give you are properties which collectively define its behaviour. – user568109 Aug 21 '14 at 13:46
  • @freakish Read http://en.wikipedia.org/wiki/Asynchronous_method_invocation. There isn't a formal *definition* for JavaScript, but it follows a lot of mentioned properties. – user568109 Aug 21 '14 at 13:52
  • @freakish Forgot to answer about your process.nextTick. this would give out of order execution : ` var c = 0; process.nextTick(function() { c++; console.log("1st run"+c); }); c++; console.log("2nd run"+c); ` – user568109 Aug 21 '14 at 14:38
2

Node.js is single threaded and runs in one process because JavaScript is single threaded. Thus you are correct.

Ivan Velichko
  • 6,348
  • 6
  • 44
  • 90
0

Yes. Javascript, including NodeJS, is single threaded (with a few exceptions).

When you use setTimeout(fn, 0), it queues up the function to run after the current call stack has cleared. In your example, that means that the for loop will complete before the "expensive tasks" get run.

GregL
  • 37,147
  • 8
  • 62
  • 67
0

Your JS code runs in a single thread in Node.js. All other native Node.js API are written in C/C++ and are either asynchronous or run on a separate thread. See this answer for the more detailed explanation.

Am I correct in understanding that while the event loop is executed synchronously, asynchronous tasks that are started, regardless of origin, are executed synchronously in the order that they were called?

Yes, you are correct.

Community
  • 1
  • 1
Oleksandr.Bezhan
  • 2,028
  • 3
  • 22
  • 31