JavaScript Async - Basic Async & Await
Written by Ian Elliot   
Monday, 01 January 2018
Article Index
JavaScript Async - Basic Async & Await
Where does the thread go?

Where Does The Thread Go?

Now we come to the most subtle point about the way that async and await work in JavaScript – and this makes it different from what might happen in other languages.

The question is, what does the thread do while a function is paused because of an await?

There are many ways of answering this and ways of thinking about it, but the best is to imagine that the await behaves like a return that can be resumed. When a function executes an await, the thread returns to the calling program which receives the Promise object created by the async function in a pending state. It really is as if a return had been executed, the only difference is that the function can resume when the Promise it is waiting for is settled.

If you find this behavior odd it is worth pointing out that it is also the way that the yield command works. A yield lets the thread resume from the point that the function was called just like a return, but again with the option of restarting.

For example consider the example:

async function myFunction(){
   var first=await delay(1000,0);
   var second=await delay(2000,0);
   return first+second;
};

What happens when myFunction is called is that the first await causes a Promise to be returned which resolves after three seconds to the value of first+second.

You can think of this as being equivalent to:

function myFunction(){
 return new Promise(function(resolve,reject) {
                   var first=await delay(1000,0);
                   var second=await delay(2000,0);
                   resolve(first+second);
                  };
};

 

This behavior has some consequences that are worth pointing out.

The first is that you can only write code that looks synchronous within an async function. At the top level you still have to work with Promises.

The second is that it is difficult, but not impossible, to use await to allow the UI thread to service the event queue. The problem is that when you use the await command the UI thread continues to run the code that called the function, and the UI thread is only freed when this terminates.

There is also the small matter that the async function cannot resume while the thread is busy running other code. In other words, the thread has to be freed and goes back to servicing the event queue in order for the async function to be resumed, or put another way the async function is resumed asynchronously.

This has a strange consequence. The first await in an async function lets the calling program continue, but the function will only resume if the calling function has terminated. This means that that any second or subsequent await in an async function will only be executed after the calling program has terminated.

Some simple examples will help make these ideas clearer.

Consider a simple pause function:

async function pause(t) {
        console.log("before");
        var promise = new Promise(
             function (resolve, reject) {
                setTimeout( function () {
                   resolve();
                   }, t);
                });
       await promise;
       console.log("after");
}

You can see the general idea is to await a Promise that takes t milliseconds to resolve. There are two console.log commands that serve to give the time before and after the await.

If you try it out from the main program:

pause(1000);

you will see the before and after messages separated by about a second. However, if you try it out using;

console.log("Before call");
pause(1000);
console.log("After call");

You will see:

Before call
before
After call

followed a second later by:

after

This should make sense if you have followed the idea that the await returns the Promise in a pending state. What happens is that “Before call” and “before” are displayed without delay, but then instead of waiting for one second the await returns control to the main program which immediately prints “After call” and then frees the UI thread. One second later the Promise resolves and the function resumes to print “after”. Not the order of events you were hoping for.

If you change the program to:

console.log("Before call"); pause(1000).then(function () {
                  console.log("After call");
                 })

then you will see the one second delay and the messages “Before call/before” followed one second later by “after/After call”.

Also notice that the await cannot be resumed until the main program has completed and this means if it is long running then the delay could be much longer than one second.

 

coverasync

 

Async & Await Summary

  • The async operator changes a function into an AsyncFunction object which has the same code, but returns a Promise.

  • The Promise is returned to the calling function in a resolved state when the async function returns a value or a resolved Promise of its own.

  • The Promise is returned to the calling function in a rejected state if the async function throws an exception or returns a rejected Promise of its own.

  • The Promise is returned to the calling function in a pending state if the async function performs an await.

  • An await which can only be used in an async function acts like a return that can be resumed.

  • You can await any Promise object and the await returns a Promise of its own that is linked to the Promise object – i.e. pending if the Promise object is pending and so on.

  • When the awaited Promise object is settled, the async function is resumed at the next instruction. The Promise object is unwrapped to its resolved value or an exception is thrown.

  • As there is no way of marking top level code as async, you cannot use await in top level code, only in an async function.

If you understand the simplicity of the way that async and await work then how to use them should be obvious, but it is worth making sure that everything is clear and it is worth looking at some potential problems.

 

Now Available as a Book:

 JavaScript Async

cover

You can buy it from: Amazon

Contents

  1. Modern JavaScript (Book Only)
  2. Events,Standard & Custom
  3. The Callback
      extract - The Callback & The Controller
  4. Custom Async - setTimeout, sendMessage & yield
      extract - Custom Async
      extract - Avoiding State With Yield 
  5. Worker Threads
      extract - Basic Worker ***NEW
      extract - Advanced Worker Threads 
  6. Consuming Promises 
  7. Producing Promises
      extract - The Revealing Constructor Pattern
     
    extract - Returning Promises
     
    extract - Composing Promises
  8. The Dispatch Queue
      extract - Microtasks
  9. Async & Await
      extract -  Basic Async & Await
      extract -  DoEvents & Microtasks
  10. Fetch, Cache & Service Worker
      extract - Fetch  
      extract - Cache
     
    extract -  Service Workers

To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.

espbook

 

Comments




or email your comment to: comments@i-programmer.info

 <ASIN:1871962528>

<ASIN:1871962501>



Last Updated ( Wednesday, 03 January 2018 )