3

I have just started react-native development and came across async functions. Can someone explain a thing or two about it in layman's terms. I have tried reading articles on it but they all tend to explain it in a very technical way which is a little confusing. I have used other languages but javaScript is not my cup of tea.

My doubts are:

  1. which one acts more like a normal function, synchronous or asynchronous function?
  2. while reading this article https://blog.expo.io/react-native-meets-async-functions-3e6f81111173 he talks about returning promises and awaiting response. so in this what is a promise and also if we are awaiting response shouldn't it be a synchronous function?
  3. And ofcourse the differences between synchronous and asynchronous function
Glitch_Znab
  • 496
  • 4
  • 13
  • 1. how does a normal function act? - 2. no, result of asynchronous functions are available asynchronously, not synchronously - 3. asynchronous functions do something that takes an unknown amount of time, javascript execution continues without waiting for the "result" - the result is always obtained via a callback mechanism - knowing that, you should have your answer to 2 and 1 – Jaromanda X Mar 03 '20 at 01:14
  • So what happens if I call an API with async function? – Glitch_Znab Mar 03 '20 at 01:26
  • 1
    With async function, you can use `await` to wait for that API call to finish before proceeding to the next line of code. Meaning, using `async` and `await` it can make your function behave like synchronous so you can avoid "callback hell" when using promises. – boosted_duck Mar 03 '20 at 01:28
  • "So what happens if I call an API with async function?" a function tagged `async` will always return a Promise - that's what happens – Jaromanda X Mar 03 '20 at 01:42
  • @boosted_duck - *make your function behave* ... no, make your function ***look*** more like it is synchronous - there's an important difference - also, Promises do not generally suffer from callback hell - that's pre-promise style callbacks that result in callback hell – Jaromanda X Mar 03 '20 at 01:43
  • Possible duplicate of [What is the difference between synchronous and asynchronous programming (in node.js)](https://stackoverflow.com/q/16336367/215552), [Asynchronous vs synchronous execution, what does it really mean?](https://stackoverflow.com/q/748175/215552), etc. But I think the question is too broad as it is currently written. – Heretic Monkey Mar 03 '20 at 01:47

2 Answers2

4

Javascript is a single-threaded language, which means that function that deals with things like I/O, Sockets and the network, in general, would block the main thread when executed. To have the ability to write concurrent code that does not block the main thread with tasks that can be slow, JS uses what is called the Event Loop. So, an async function is just a function that can be put in a queue and have the results of the function checked in later, without blocking the main thread.

You can find out more about the Event Loop on MDN and watching this talk by Philip Roberts

404
  • 8,022
  • 2
  • 27
  • 47
3

This is a challenging topic when coming from other programming languages. Using your terminology, a 'normal' function is akin to a synchronous function.

I'd recommend the MDN docs for await. Read that page and then run the f1 example -- I've included it below with a couple of enhancements:

  1. I've added timestamps to console.log so timing is more obvious
  2. I've added console.log statements immediately before and after the call to f1().

The await keyword doesn't mean wait (or block) when inside an async function. It splits the execution flow, pausing the f1 function (which will be resumed about 2 seconds later) and returning a Promise that allows callers of the async function to choose if they want to await the result of the async function or not. In the code below, we print out the result of the call to f1() but we choose not to await the deferred result and we just continue onwards to the next console.log.

Run this code in Node.js:

///////////////////////////////////////////////////////////////////////
// This is just setting up timestamps for console.log
///////////////////////////////////////////////////////////////////////
const oldlog = console.log;

console.log = function () {
  var args = [].slice.call(arguments);
  oldlog.apply(console.log,[getTimestamp()].concat(args));
};

const getTimestamp = () => '[' + (new Date()).toISOString() + ']';

///////////////////////////////////////////////////////////////////////
// Real code starts here
///////////////////////////////////////////////////////////////////////
function resolveAfter2Seconds(x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}

async function f1() {
  console.log('enter f1');
  const x = await resolveAfter2Seconds(10);
  console.log('exit f1, x =', x);
  return x;
}

console.log('before f1');
const y = f1();
console.log('after f1, y =', y);

When run, this will result in something like the following:

[2020-03-03T01:48:50.716Z] before f1
[2020-03-03T01:48:50.719Z] enter f1
[2020-03-03T01:48:50.720Z] after f1, y = Promise { <pending> }
[2020-03-03T01:48:52.725Z] exit f1, x = 10

Note specifically that we see the after f1 log before we see the exit f1 log. The execution flow was split and f1() was paused while the caller of f1() continued. The execution of f1() resumed about 2 seconds later.

Now, compare that with what happens if we instead await the result from calling f1(). Note that because we are now using await we must wrap the code in async (an async IIFE, actually) because await can only be used inside an async function.

// console.log('before f1');
// const y = f1();
// console.log('after f1, y =', y);

(async () => {
  console.log('before f1');
  const y = await f1();
  console.log('after f1, y =', y);
})();

Now, the output is as follows:

[2020-03-03T02:19:18.122Z] before f1
[2020-03-03T02:19:18.124Z] enter f1
[2020-03-03T02:19:20.130Z] exit f1, x = 10
[2020-03-03T02:19:20.130Z] after f1, y = 10

Note that now, because the caller chose to await the result of calling f1(), we see the after f1 and exit f1 logs reversed (and in the 'normal' order, using your terminology). And now the result of f1() is 10, rather than a pending Promise.

So, this is mildly tricky stuff and I encourage more reading and experimentation to get to grips with it. It looks complex but it is actually simpler to write asynchronous JavaScript code now than it was prior to the introduction of async/await into the language.

jarmod
  • 71,565
  • 16
  • 115
  • 122
  • 1
    Thank you very much for the explanation and also for clearly understanding what i was talking about. Thanks again – Glitch_Znab Mar 03 '20 at 02:51
  • I was puzzled by the various descriptions of async - from what I read in MDN, it seemed that the *only* effect of adding the async keyword to a function definition was that it permitted that function to use the await operator. Using jquery I had a collection of elements I needed to loop over, and process code for each one that called a sequence of functions returning promises that needed to be resolved before the next function could be called. So I naturally used $.each(). And since the processing needed to use await, I just made the callback function async. Big mistake! -cont'd – sootsnoot Feb 25 '23 at 16:33
  • Doing this apparently allowed the processing for the different elements in the collection to overlap. The processing was using pdf-lib to edit a pdf, and the resulting pdf made it look like pdf-lib was badly broken. To fix it, I had to change the $.each() loop into an explicit loop over elements, and at the end of the explicit loop await the async function that called (and awaited) the sequence of functions returning promises. This prevented the processing of different elements from overlapping. – sootsnoot Feb 25 '23 at 16:42
  • 1
    @sootsnoot Yes, if you need to serialize N asynchronous calls, for example when the input to iteration K depends on the output of iteration K-1, then you have to be careful how you loop. More info [here](https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop) and [here](https://jrsinclair.com/articles/2019/how-to-run-async-js-in-parallel-or-sequential/). – jarmod Feb 25 '23 at 17:19
  • @jarmod Thanks for the references. I do find it strange that the MDN description of async doesn't seem to say that besides allowing you to use the await operator within a function , adding async to a function definition changes the behavior of the function such that it may be run asynchronously (which seems like the obvious intuitive interpretation of the keyword, but the docs don't say anything to confirm it). – sootsnoot Feb 25 '23 at 17:53