Understanding Asynchronous Code in Layman's Terms

Understanding Asynchronous Code in Layman's terms

I'm not sure where this function is being used, but the point of callbacks is that you pass them into some function that runs asynchronously; it stores your callback away, and when that function is done with whatever it needs to do, it will call your callback with the necessary parameters. An example from front-to-back is probably best.

Imagine we have a framework, and in it there is an operation that runs for a long time, fetching some data from the database.

function getStuffFromDatabase() {
// this takes a long time
};

Since we don't want it to run synchronously, we'll allow the user to pass in a callback.

function getStuffFromDatabase(callback) {
// this takes a long time
};

We'll simulate taking a long time with a call to setTimeout; we'll also pretend we got some data from the database, but we'll just hardcode a string value.

function getStuffFromDatabase(callback) {
setTimeout(function() {
var results = "database data";
}, 5000);
};

Finally, once we have the data, we'll call the callback given to us by the user of the framework's function.

function getStuffFromDatabase(callback) {
setTimeout(function() {
var results = "database data";
callback(results);
}, 5000);
};

As a user of the framework, you'd do something like this to use the function:

getStuffFromDatabase(function(data) {
console.log("The database data is " + data);
});

So, as you can see data (same as response and postData in your example) came from the function that you pass your callback into; it gives that data to you when it knows what that data should be.

The reason you can't set a value in your callback and use it outside the callback is because the callback itself doesn't happen until later in time.

//  executed immediately  executed sometime in the future
// | | by getStuffFromDatabase
// v v
getStuffFromDatabase(function(data) {
var results = data; // <- this isn't available until sometime in the future!
});

console.log(results); // <- executed immediately

When the console.log runs, the assignment of var results hasn't happened yet!

Easy to understand definition of asynchronous event?

Non programming example:

Synchronous
You want a pizza for dinner and you are out of the frozen kind. So you have to stop playing WOW which upsets your guild. You go to the kitchen, make the dough, cover it with sauce, add the cheese, and smother it your favorite bacon topping. You just spent 20 minutes of your time making the pizza with another 10 minutes in the oven. The timer beeps and you pull the hot pie out. You can sit back down in front of your computer, eat the pizza, and continue with your raid.

Asynchronous
You want a pizza for dinner while playing WOW. You open up a browser window on your 5th monitor. You load up the Pizza website and order your extra cheesy bacon pizza with a side of bacon grease garlic sauce. You go back to your raid and after 20 minutes the door bell rings. You get the pizza. You sit back down in front of your computer, eat the pizza, and continue with your raid.

So what is the difference? One way you waste 20-30 minutes of precious WOW time, the other way you waste $20 plus tip.

Asynchronous Vs Synchronous Code In JavaScript

Long answer short, JavaScript is not completely single threaded. While execution, internal threads are created to handle Async functionality like xmlhttprequest.

Now coming to your doubts,

  1. Yes if the request is Async like an I/O operation, depending on the JavaScript Engine it creates separate thread for it and executes in background while the main process still runs, once the Call Stack is empty the Event Loop pushes the tasks available in Callback Queue ( having your callback function that gets called when a action is completed) to the Call Stack and runs it.

  2. Again this depends on Engine on which the program is getting executed. The Node.js uses V8 Engine which has access to Thread pool provided by libuv which creates limited no. of threads and assign tasks to each one of them. For example 10 requests to download a file may be handled by first creating 4 threads to download file for first 4 requests, after downloaded again download other 4, then finally the rest 2 files get downloaded. Callback functions get called in the same order.

  3. setInterval, setTimeout, xmlhttprequest are functionalities which are provided additionally and is not part of native JavaScript. So whenever such function is called, external packages work on it while still the main JavaScript program continues to run, when the Async function gets finished it simply calls the Callback function with the result data. As you are familiar with Event Loop, it is the one which handles calling the Callback function from Callback Queue.

  4. As I said each browser has different JavaScript Engine and has different ways to handle things. NodeJS uses Google's V8 Engine and has a package called libuv which handles Async stuff. I would suggest you to refer below link:

Overview of Blocking vs Non-Blocking in NodeJS

Asynchronous vs synchronous execution. What is the difference?

When you execute something synchronously, you wait for it to finish before moving on to another task. When you execute something asynchronously, you can move on to another task before it finishes.

In the context of operating systems, this corresponds to executing a process or task on a "thread." A thread is a series of commands (a block of code) that exist as a unit of work. The operating system runs a given thread on a processor core. However, a processor core can only execute a single thread at once. It has no concept of running multiple threads simultaneously. The operating system can provide the illusion of running multiple threads at once by running each thread for a small slice of time (such as 1ms), and continuously switching between threads.

Now, if you introduce multiple processor cores into the mix, then threads CAN execute at the same time. The operating system can allocate time to one thread on the first processor core, then allocate the same block of time to another thread on a different processor core. All of this is about allowing the operating system to manage the completion of your task while you can go on in your code and do other things.

Asynchronous programming is a complicated topic because of the semantics of how things tie together when you can do them at the same time. There are numerous articles and books on the subject; have a look!

Simple question about asynchronous programming

Despite being imprecise about the thread being blocked (which is incorrect as pointed out in the comments),
you are correct.

While 'more performing' may mean many things, assuming that both operations are independent, Task.WhenAll option will finish earlier.

Having

var work1 = async () => await Task.Delay(1000);
var work2 = async () => await Task.Delay(2000);
await work1();
await work2();

will take 3 seconds,
and

await Task.WhenAll(work1(), work2());

will take 2 seconds.

Understanding F# Asynchronous Programming

The "async" in this example is not about concurrency or saving time, rather it's about providing a good programming model without blocking (read: wasting) threads.

If using other programming languages, typically you have two choices:

You can block, typically by calling synchronous methods. The disadvantage is that the thread is consumed and doing no useful work while it waits for the disk or network I/O or what have you. The advantage is it the code simple (normal code).

You can use callbacks to call asynchronously and get notifications when operations complete. The advantage is you don't block threads (these threads can be returned e.g. to the ThreadPool and a new ThreadPool thread will be used when the operation completes to call you back). The disadvantage is that a simple block of code gets divided up into a bunch of callback methods or lambdas, and it quickly becomes very complicated to maintain state/control-flow/exception-handling across the callbacks.

So you're between a rock and a hard place; you either give up the simple programming model or you waste threads.

The F# model gives the best of both worlds; you don't block threads, but you keep the straightforward programming model. Constructs like let! enable you to 'thread-hop' in the middle of an async block, so in code like

Blah1()
let! x = AsyncOp()
Blah2()

Blah1 may run on, say, ThreadPool thread #13, but then AsyncOp will release that thread back to the ThreadPool. Later when the AsyncOp completes, the rest of the code will start back up on an available thread (maybe, say, ThreadPool thread #20) which binds x to the result and then runs Blah2. In trivial client apps this rarely matters (except when ensuring you don't block the UI thread), but in server apps that do I/O (where threads are often a precious resource - threads are expensive and you can't waste them by blocking) non-blocking I/O is often the only way to make an application scale. F# enables you to write non-blocking I/O without having the program degrade into a mass of spaghetti-code callbacks.

See also

Best practices to parallelize using async workflow

How to do chained callbacks in F#?

http://cs.hubfs.net/forums/thread/8262.aspx

How and when to use ‘async’ and ‘await’

When using async and await the compiler generates a state machine in the background.

Here's an example on which I hope I can explain some of the high-level details that are going on:

public async Task MyMethodAsync()
{
Task<int> longRunningTask = LongRunningOperationAsync();
// independent work which doesn't need the result of LongRunningOperationAsync can be done here

//and now we call await on the task
int result = await longRunningTask;
//use the result
Console.WriteLine(result);
}

public async Task<int> LongRunningOperationAsync() // assume we return an int from this long running operation
{
await Task.Delay(1000); // 1 second delay
return 1;
}

OK, so what happens here:

  1. Task<int> longRunningTask = LongRunningOperationAsync(); starts executing LongRunningOperation

  2. Independent work is done on let's assume the Main Thread (Thread ID = 1) then await longRunningTask is reached.

    Now, if the longRunningTask hasn't finished and it is still running, MyMethodAsync() will return to its calling method, thus the main thread doesn't get blocked. When the longRunningTask is done then a thread from the ThreadPool (can be any thread) will return to MyMethodAsync() in its previous context and continue execution (in this case printing the result to the console).

A second case would be that the longRunningTask has already finished its execution and the result is available. When reaching the await longRunningTask we already have the result so the code will continue executing on the very same thread. (in this case printing result to console). Of course this is not the case for the above example, where there's a Task.Delay(1000) involved.

Understanding async/await on NodeJS

To clear a few doubts -

  1. You can use await with any function which returns a promise. The function you're awaiting doesn't need to be async necessarily.
  2. You should use async functions when you want to use the await keyword inside that function. If you're not gonna be using the await keyword inside a function then you don't need to make that function async.
  3. async functions by default return a promise. That is the reason that you're able to await async functions.

From MDN -

When an async function is called, it returns a Promise.

As far as your code is concerned, it could be written like this -

const getUsers = (ms) => { // No need to make this async
return new Promise(resolve => setTimeout(resolve, ms));
};

// this function is async as we need to use await inside it
export const index = async (req, res) => {
await getUsers(5000);

res.json([
{
id: 1,
name: 'John Doe',
},
{ id: 2,
name: 'Jane Doe',
},
]);
};


Related Topics



Leave a reply



Submit