19

New TypeScript async/await feature uses ES6 promises. AngularJS uses $q service promises with slightly different interface.

Is there any way to use TypeScript async/await feature with $q service promises?

2
  • 1
    Yes. The first problem is that I have to convert every promise-response from ng-service to use await against it. The second problem is that ES6-promises generated by await expression don't start angular digest cycle Commented Feb 26, 2016 at 14:07
  • There is an open issue about this github.com/Microsoft/TypeScript/issues/6122 Commented Jul 24, 2018 at 10:42

3 Answers 3

15

You can make it work like this:

angular.module('your app')
        .run(['$window', '$q', function($window, $q) {
            $window.Promise = $q;
        }]);
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you, it's much more neat than my version. I didn't know that $q service can be used as a constructor compatible with es6-promises
This works, and I'm using it in several projects now. But I can't help but shake the feeling that this is naughty. Replacing the global Promise object with the Angular $q service seems...hackish.
Replacing native Promise with $q is probably the worst thing the one can ever do to the application. They are fundamentally different implementations that behave differently, this will ruin all third-party code that depends on Promise. The statement about 'hackish' $window is false - it's there not because Angular is incapable of using native window, but because DI is good.
@estus So what should we do instead? I've been looking all over the web to get async / await working decently with AngularJS but I cannot find a good consensus.
@Schoof By the way, the answer won't work for native async (TypeScript es2017 target) any way, because it relies on internal native implementation and not Promise global. See stackoverflow.com/a/45119519/3731501 for instance . A digest should be triggered after async function execution in more or less explicit manner.
5

I do not think you will be able to use them directly. But it should be quite easy to convert q promise into a++ promise, something like this:

function Convert<T>(qPromise): Promise<T> 
{
    return new Promise<T>((resolve, reject) =>
    {
        qPromise.then((result: T) => resolve(result), (e) => reject(e));
    });
};

1 Comment

The problem is that in this case I have to wrap each ng service that returns $q promises. Also, ES6-promises don't initiate angular digest cycle. So, in this case I have to call $apply after each await
1

Finally I used the following workaround:

declare var __awaiter: Function;
(window as any).__awaiter = __awaiter; // set global __awaiter to avoid declaring default __awaiter in other files
async () => { } // dummy async function to generate __awaiter code for current file

angular.module('ts-awaiter', []).run(['$timeout', ($timeout: ng.ITimeoutService) => {
    function wrap(func: Function) {
        return function () {
            func.apply(this, arguments);
            $timeout(() => { }); // run angular digest
        };
    }

    var oldAwaiter = __awaiter;
    (window as any).__awaiter = (thisArg: any, _arguments: any, P: Function, generator: any) => {
        P = function (executor: Function) {
            return new Promise<any>((resolve, reject) => {
                resolve = wrap(resolve);
                reject = wrap(reject);
                executor(resolve, reject);
            });
        };
        return oldAwaiter(thisArg, _arguments, P, generator);
    };
}]);

Comliper for Typescript 1.8 generates __awaiter function in every file where await operator is used. I replace it with implementation which passes custom Promise constructor which initiates digest cycle after every resolve and reject call. Here is usage example: https://github.com/llRandom/ts-awaiter

3 Comments

Just out of curiosity how does this handle rejects? catch block?
Yes. Added an example to the repository
This may result in unneeded digests, and digests are the most common bottleneck for AngularJS app performance. And the solution is not applicable to TypeScript ES2017 target... native async/await is already there.

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.