24

I am trying to grasp on Javascript Asynchronous functions and callbacks.

I got stuck on the concept of callback functions, where I am reading on some places: they are use to have sequential execution of code (mostly in context of jquery e.g animate)and some places specially in the context of Nodejs; they are use to have a parallel execution Asynchronous and avoid blocking of code.

So can some expert in this topic please shed light on this and clear this fuzz in my mind (examples??). so I could make my mind for the usage of callback function

or that is solely depends on the place of where you are calling/placing a callback function in your code? .

Thanks,

P.S: I am scared that this question would be close as subjective but still I could expect concrete answer for this (perhaps some examples)

Edit: actually this is the example from internet which makes me ambigous:

function do_a(){
  // simulate a time consuming function
  setTimeout( function(){
    console.log( '`do_a`: this takes longer than `do_b`' );
  }, 1000 );
}

function do_b(){
  console.log( '`do_b`: this is supposed to come out after `do_a` but it comes out before `do_a`' );
}

do_a();
do_b();

Result

`do_b`: this is supposed to come out after `do_a` but it comes out before `do_a`
`do_a`: this takes longer than `do_b`

when JS is sequential then do_b should always come after do_a according to my understanding.

3
  • 8
    JavaScript is JavaScript; it's dependent on context, usage, engine, etc. Commented May 13, 2013 at 14:00
  • Can you provide some example code that you're not sure if it is blocking vs nonblocking? Commented May 13, 2013 at 14:06
  • JavaScript is in general synchronous, but setTimeout is asynchronous by definition. Here's a good primer on it: developer.mozilla.org/en-US/docs/DOM/window.setTimeout Commented May 13, 2013 at 14:25

5 Answers 5

28

The core of JavaScript is largely synchronous, in that functions complete their task fully, before completing. Prior to the advent of AJAX, it was really only setTimeout and setInterval that provided asynchronous behavior.

However, it's easy to forget that event handlers are, effectively async code. Attaching a handler does not invoke the handler code and that code isn't executed until some unknowable time in the future.

Then came AJAX, with its calls to the server. These calls could be configured to be synchronous, but developers generally preferred async calls and used callback methods to implement them.

Then, we saw the proliferation of JS libraries and toolkits. These strove to homogenize different browsers' implementations of things and built on the callback approach to async code. You also started to see a lot more synchronous callbacks for things like array iteration or CSS query result handling.

Now, we are seeing Deferreds and Promises in the mix. These are objects that represent the value of a long running operation and provide an API for handling that value when it arrives.

NodeJS leans towards an async approach to many things; that much is true. However this is more a design decision on their part, rather than any inherent async nature of JS.

Sign up to request clarification or add additional context in comments.

Comments

14

Javascript is always a synchronous(blocking) single thread language but we can make Javascript act Asynchronous through programming.

Synchronous code:

console.log('a');
console.log('b');

Asynchronous code:

console.log('a');
setTimeout(function() {
    console.log('b');
}, 1000);
setTimeout(function() {
    console.log('c');
}, 1000);
setTimeout(function() {
    console.log('d');
}, 1000);
console.log('e');

This outputs: a e b c d

2 Comments

what does blocking mean in this context?
@SandeepanNath You may have already figured it out, but for future visitors: blocking refers to serial processing. Doing one thing at a time. On the other hand, non-blocking code (asynchronous) can run in parallel (or multithreaded). The advantage is that it can be faster.
5

I know this is old, but I came across this searching for the same thing, am not satisfied with any of the answers, and see that it gets a new answer every few years, so I'll add mine.

TL;DR;

Javascript is synchronous. Any running code will block any other code that tries to run. Web Workers are synchronous, but they are essentially a new, hidden, browser window (a separate thread) so they are executing their code synchronously, separately. What you can do is run your code in an indeterminate order. You can use events, setTimeout/setInterval, promises, etc to break your code into separate chunks with different trigger criteria and let the browser run them in whatever order that criteria ends up producing. This gives a semblance of asynchronicity, but the browser will still only run one chunk at a time, and that chunk will have to complete before the next chunk is run, regardless of whether those chunks run any of the same routines or not. You can use web workers to move code into a separate thread, but that code is truly separate, with no asynchronous interaction with the original code. The worker code is still synchronous within its thread, and communication between the worker and the browser still won't let either one run more than one thing at a time (ie, a worker isn't going to process an event if it's doing something else). In a lot of languages you have to jump through hoops to make sure your code works if it ever happens to be run by multiple threads. In Javascript, those issues are not possible, and you would have to intentionally jump through a lot of hoops just to simulate those types of problems.

This fiddle shows a comparison between async and promises, demonstrating basically what an async function really is and what long-running tasks do. (https://jsfiddle.net/g23ptkxz/)

This fiddle shows a basic web worker and what happens when the worker is running a long task, proving the lack of asynchronicity between the threads. (https://jsfiddle.net/wojqad3x/)

Javascript is synchronous

Javascript is synchronous, period. Anything running in a webpage (even if it's multiple imported script files) will block anything else that tries to run. What callbacks let you do is hand a function to the browser to be run at some point later. So when you call setTimeout, you aren't executing javascript code asynchronously, you are just handing it to the browser so that it can be executed synchronously, but out of order, later.

Using setTimeout as an example, you tell the browser to run it when a certain amount of time passes. The browser will then ATTEMPT to call your function. But that function is still part of your web page, so if you are still doing anything, you will block the browser and it will have to wait. So if you call setTimeout(x,3000), and then do some work that takes 20 seconds, it will be at least 20 seconds before x gets called.

Promises

Promises are the exact same thing. I don't truly even consider the function you pass to the constructor of a Promise a "callback"; it is executed immediately just as if you had replaced the new Promise() line with the constructor function code. So

doSomething();
new Promise((resolve, reject) => {
  doSomething2();
  doSomething3();
  resolve();
});
doSomething4();

is the exact same thing as

doSomething();
doSomething2();
doSomething3();
doSomething4();

So the constructor function definitely blocks; doSomething4 isn't going to be run until doSomething3 completes, regardless of whether it is in a promise constructor function or not. Now, the "then" portion is just like the setTimeout, where you are handing that function off to the browser. But instead of saying "run this when this much time passes", you are telling it "run this after I call the resolve callback". So again, that "then" function is part of your existing script. So if you call resolve and then continue doing some long work (eg, doSomething4() takes a long time) the "then" function still isn't going to get called for a while, because the browser will have to wait.

One fancy bit of this is that the browser is guaranteed to wait. So when the promise spec talks about "guaranteed to be asynchronous", it means "guaranteed to run out of order".

doSomething();
new Promise((resolve, reject) => {
    doSomething2();
    doSomething3();
    resolve();
}).then(doSomething5);
doSomething4();

In this example, doSomething5 is guaranteed to not be called until after doSomething4, even though the promise has been resolved before the promise constructor even completes. And if you've already had several other setTimeouts or events or whatever that have been blocked, those are all going to run before doSomething5 does.

Async/Await

Async/Await is just a wrapper around promises. Your code goes into the constructor, so if you don't call anything that does an await, your function executes completely before the next line after the call is executed, regardless of whether you call the function with async or not.

async function doStuff() {
    doSomething2();
    doSomething3();
}
doSomething1();
await doStuff();
doSomething4();

is essentially

function doStuff() {
    const p = new Promise((resolve,reject) => {
        doSomething2();
        doSomething3();
        resolve();
    });
    return p;
}
doSomething1();
doStuff().then(() => {
    doSomething4();
});

If this is all you have, the execution is identical to running without async/await. The differences come in that "guaranteed out of order" stuff; if done this way...

async function doStuff2and3() {
   doSomething2();
   doSomething3();
}
async function doStuff1to4() {
   doSomething1();
   await doStuff2and3();
   doSomething4();
}
doStuff1to4();
doSomething5();

the "then" becomes important. In this case, since doSomething4 is essentially in a "then" and guaranteed to run out of order, and you didn't call doStuff1to4 with "await", doSomething4 won't run until after doSomething5.

I have a fiddler here (https://jsfiddle.net/g23ptkxz/) that has a long-running task written in promises and async, showing that they act exactly the same.

Web Workers are Synchronous

Workers throw a slight (very slight) wrench in the works. The easiest way to think of it is that a web worker is another browser window (I think the technical term is "execution context"). The "new browser window" can do whatever it wants and it has nothing to do with whatever you are doing. But that's where the asynchronicity ends. The code in the web worker will block other code in the web worker just like your main code does. If the web worker is doing anything and you try to post a message to it, that message isn't going to go in until the web worker isn't doing anything. But, since that communication is another "outside of javascript" thing, it won't block your browser; your message just goes into the same queue as any other currently-blocked events or whatever and will execute in the worker whenever everything before it finishes. The main thread has no knowledge of when that is, since the postMessage call is "fire and forget".

I have a fiddle here (https://jsfiddle.net/wojqad3x/) with a basic web worker set up to demonstrate. It spawns a web worker and both the worker and the browser start counters. Clicking the add or sub buttons adjust the number the web worker is generating, and the two scripts post messages back and forth to each other. If you click "longRunner", you'll see that the counter for the worker stops because the message event locks up the worker and blocks everything else. The main browser isn't locked, so that counter keeps going. You can click add1 and sub1 while longRunner is active and you'll see that none of their processing gets done until after longRunner completes. And when longRunner does complete, it generates a message that includes the current total adjustment that add1 and sub1 have made, so you can see it isn't just the messaging display that has stopped, the adjustment doesn't get applied at all until longRunner finishes.

Node's process.nextTick

process.nextTick(foo) is exactly the same thing as Promise.resolve().then(foo). Process.nextTick is node's way of saying "I guarantee foo will be run out of order". It does the same thing "then" does; it takes that function call and adds it to the event queue to be run after whatever is currently running finishes.

(Updated version of the link from Adam's answer. (https://howtonode-org.vercel.app/understanding-process-next-tick.html))

What it all boils down to

The main takeaway is that you don't have to worry about thread safe coding and race conditions and such in javascript. No section of code will ever be run by multiple things.

const _list = [];
function addItem(item) {
   _list.push(item);
   startWatcher();
}
function removeItem(itemKey) {
   for (let i = 0; i < _list.length; ++i) {
      if (_list[i].key == itemKey) {
         _list.splice(i, 1);
         break;
      }
   }
}
let _watcherHandle;
function startWatcher() {
   if (_watcherHandle) return;
   function handler() {
      for (let i = _list.length - 1; i >= 0; --i) {
         if (_list[i].needsRemoval) {
            removeItem(_list[i].key);
         }
      }
   }
   _watcherHandle = startInterval(handler, 1000);
}
function stopWatcher() {
   clearInterval(_watcherHandle);
   _watcherHandle = 0;
}

This section of code is a nightmare in an asynchronous language. Something could be added between the check for the length of the array and the time the interval is cleared, so that the interval stops with an item in the array. Or it could be added after the interval is cleared but before the handle is set to 0, so the interval doesn't restart. Or something could be inserted into the array that needs to be removed while the array is already being processed, so it would get missed until the next interval. Some other thread could completely empty the array while the watcher was still processing and cause errors with invalid indexes.

In javascript, none of that can happen. It's using setInterval, so you don't know exactly when the watcher handler will be called. Any of the other routines may be called by any number of promises, or events (even message events from another worker), or other intervals/timeouts, so you may not know the ORDER of any of the executions beforehand. But you DO know that it is all one script, so if any section of that code is executing, it's going to execute to completion with no interference. If, for some masochistic reason, you wanted to have the possibility of race conditions and such, you would have to break every line out into its own promise/async/eventHandler or whatever so that you didn't know the order that the individual operations within a call would happen in. It's not something you do by accident.

3 Comments

I like your answer, i am learning javascript and it was quite useful however you said "you don't have to worry about thread safe coding and race conditions and such in javascript. No section of code will ever be run by multiple things." which is incorrect (see: stackoverflow.com/a/73202896/12970235 )
The example in your link is really what I was referring to when I said ... you would have to break every line out into its own promise/async/eventHandler or whatever so that you didn't know the order that the individual operations within a call would happen in.... The example takes y=x and then intentionally adds an async process before doing x = y+1. So, yes, you don't necessarily know the result of x, but you are also intentionally setting it that way, it's not an accidental race. In a true multithreaded app, you couldn't rely on the result even without the async delay.
I'll admit that there may be cases where you've set up very complicated code that happens to have some async and ends up where you get in this situation unintentionally, but I'd lay the blame then down to writing code that's so complicated you didn't realize there's an async, rather than to the async processing itself. :)
3

In node long running processes use process.nextTick() to queue up the functions/callbacks. This is usually done in the API of node and unless your programming(outside the api) with something that is blocking or code that is long running then it doesn't really effect you much. The link below should explain it better then I can.

howtonode process.nextTick()

jQuery AJAX also takes callbacks and such as it its coded not to wait for server responses before moving on to the next block of code. It just rememebers the function to run when the server responds. This is based on XMLHTTPRequest object that the browsers expose. The XHR object will remember the function to call back when the response returns.

setTimeout(fn, 0) of javascript will run a function once the call stack is empty (next available free tick) which can be used to create async like features.setTimeout(fn, 0) question on stackoverflow

To summerise the async abilities of javascript is as much to do with the environments they are programmed in as javascript itself. You do not gain any magic by just using lots of function calls and callbacks unless your using some API/script.

Jquery Deferred Object Is another good link for async capabilities of jQuery. Googling might find you information on how jQuery Deferred works also for more insight.

Comments

1

In JavaScript the term "asynchronous" typically refers to code that gets executed when the call stack is empty and the engine picks a job from one of its job queues for execution.

Once code is being executed, it represents a synchronous sequence of execution, which continues until the call stack is empty again. This sequence of execution will not be interrupted by events in order to execute some other JavaScript code (when we discard Web Workers). In other words, a single JavaScript environment has no preemptive concurrency.

While synchronous execution is ongoing, events might be registered as jobs in some job queues, but the engine will not process those before first properly execution what is on the call stack. Only when the call stack is empty will the engine take notice of the job queues, pick one according to priority, and execute it (and that is called asynchronous).

Callbacks

Callbacks can be synchronous or asynchronous -- this really depends on how they are called.

For instance, here the callback is executed synchronously:

new Promise(function (resolve) { /*  .... */ });

And here the callback is executed asynchronously:

setTimeout(function () { /* ... */ });

It really depends on the function that takes the callback as argument; how it deals with eventually calling that callback.

Ways to get code to execute asynchronously

The core ECMAScript language does not offer a lot of ways to do this. The well-known ones are offered via other APIs, such as the Web API, which are not part of the core language (setTimeout, setInterval, requestAnimationFrame, fetch, queueMicrotask, addEventListener, ...).

Core ECMAScript offers Promise.prototype.then and (depending on that) await. The callback passed to then is guaranteed to execute asynchronously. await will ensure that the next statements in the same function will be executed asynchronously: await makes the current function return, and this function's execution context will be restored and resumed by a job.

It also offers listening to when the garbage collector is about to garbage collect an object, with FinalizationRegistry.

Web Workers

Web Workers will execute in a separate execution environment, with their own call stack. Here preemptive concurrency is possible. When the term asynchronous is used in the JavaScript world, it typically does not refer to this kind of parallelism, although the communication with a Web Worker happens via asynchronous callback functions.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.