4

Have a look at the following Angular 1.x controller:

class RootController
{
    constructor($http)
    {
        this.variable = "apples";
        // this.test($http);      -- this works
        // this.asyncTest($http); -- this doesn't
    }

    async asyncTest($http)
    {
        await $http.get('/api/someApiCall');
        this.variable = "oranges";
        // await $http.get('/api/someApiCall'); -- this makes this method work
    }

    test($http)
    {
        $http.get('/api/someApiCall').then(() => {
            this.variable = "oranges";
        });
    }
}

If we uncomment one of the two commented out lines in the constructor, we get different behavior. If we run test(), then variable gets updates to the value "oranges" and displays in the view, as expected. If we run asyncTest(), the view continues to display "apples" until something forces a digest (for some reason clicking in and out of a textbox seems to do the trick).

Another weird issue is that if we uncomment out the second await in asyncTest(), then that method now works as expected.

Why does this happen, and why does the second await fix it? I thought await was pretty much just syntactic sugar for then, so these should be completely equivalent. I found some articles talking about this issue but they're more about how to fix it than what's going on under the hood.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Jack M
  • 4,769
  • 6
  • 43
  • 67

1 Answers1

1

As far as I understand Async Await functionality in Javascript is implemented using a clever combination of Promises and Generators which is too clever for me to explain in detail. But you can take a look at these if you are interested : https://chromium.googlesource.com/v8/v8.git/+/d08c0304c5779223d6c468373af4815ec3ccdb84/src/js/harmony-async-await.js#34

https://curiosity-driven.org/promises-and-generators

async/await native implementations

So since the Promise is resolved and the Angular dirty checking / digest cycle will be completed before the generator yields, your this.variable = "oranges"; inside the asyncTest function wouldn't be reflected in the UI. But when you add the commented out line await $http.get('/api/someApiCall'); in the asyncTest function, the dirty checking / digest cycle will be triggered again, thereby updating the UI. The same thing happens when you focus out of some field like text boxes.

Since inside the test function you are doing this.variable = "oranges"; inside the then, everything works fine.

ajaybc
  • 4,049
  • 7
  • 44
  • 57