4

We have an Angular 1.5 application built with Typescript, and I am trying to figure out the best way to deal with ng.IPromise vs Promise (ES6 promise). My preference would be to only deal with the ES6 Promise type. Is there an elegant way to override all angular-js and angular-material (also included) interfaces to use es6 promises?

Options I can think of:

  1. Use some d.ts magic to do this (can it be done?)
  2. Cast to ES6 Promise everywhere (works, but not intuitive)
  3. Contribute to open source, fork the typings for ng and ng material, and make them return type of ES6 Promise (I probably should just do this, but not sure I have time for a rabbit hole right now)

Clarification

The underlying Promise implementation used by the angular application is still $q (though, I am also applying angular-bluebird-promises). I'm only trying to simplify/consolidate the Typescript interfaces involved.

Ken
  • 834
  • 9
  • 25
  • $q promises shouldn't be blindly replaced with native promises because there are fundamental differences between them. They are different things. $q chain can be synchronous and runs on digest. This does not apply to other promise implementations. – Estus Flask Jun 30 '16 at 12:45
  • I'm still using $q promises (clarification added) – Ken Jun 30 '16 at 14:14
  • Then they should remain two different interfaces, because they refer to different constructors. That have different... interfaces. You can aggregate them to common denominator, e.g. IPromise, because in ES6/TS app $q and native promises may co-exist. But it makes very little sense. Accidentally using native promise in a piece of code that expects $q promise is the last thing you want to do. So again, these interfaces shouldn't be mixed – Estus Flask Jun 30 '16 at 14:27
  • @estus, that makes sense. please answer and I'll accept – Ken Jun 30 '16 at 15:31
  • @Ken i'm facing the same affair, i like to write some new code without hardwiring my library to angular, so basically i want to return an IHTTPPRomsie to Promsie, i do know that the then/catch/ffinally handlers functions run within angularjs digest cicle, so in order to be angular compliant i was thinking to wrap with $timeout those parts that require to be angularjs aware ... well very interesting! – Victor Feb 08 '22 at 00:06

2 Answers2

6

There are very good reasons why they should remain two different interfaces.

There are fundamental differences between $q promises and other implementations. $q chain can be synchronous and runs on digest. This does not apply to other promises (namely, native Promise).

In TS/ES6 application where native and $q promises coexist, Promise and ng.IPromise interfaces can be aggregated to common denominator that fits both of them, e.g. IPromise (without ng). But it makes very little sense. Accidental use of native promise in a piece of code that expects $q promise (and vice versa) is the last thing you want to do, but it won't be prevented by Typescript if common IPromise is being used.

If the promise is expected to be exported from Angular and used by non-Angular code, it is preferable to convert it to Promise, as the other answer suggests.

For given non-Angular context

let exportedPromise = getResolvedPromise();
...
exportedPromise.then(...);

this

function getResolvedPromise() {
  return Promise.resolve($q.resolve());
};

will fire then callback on next tick. And this

function getResolvedPromise() {
  return $q.resolve();
};

will pause the chain till next root scope digest, even though then has been chained on resolved promise.

While not being relevant to TS, this question is a good example why it is important to always be aware of whether it is $q or native promise that is used.

Community
  • 1
  • 1
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • i wonder this ¿what would be the differnce on executing code in the same tick or in another? as long the two of them are within an angularjs digest cicle i don't know if the outcome will be different. I guess you shall wrap with `$timeout` in the example using native promises and that is all, on the next tick, angular will digest your changes, right? – Victor Feb 08 '22 at 00:03
  • 1
    There may be a difference in case of race conditions, i.e. when multiple piece of code are executed in wrong order because they are execute at different moments of time. Otherwise, if it works, it works. Executing the code in the next tick may give some time for DOM to radraw and be better for UX, but this needs to be checked. With native promises an additional timeout is exhaustive, a digest can be just triggered with $scope.$apply(). – Estus Flask Feb 08 '22 at 09:13
  • race conditions in javascript on a browser... i thought that is impossible... as there a no threats in javascript, perhaps not in the projects i work... i do know about something called workers but i don't know, i never has to really use them... nevertheless the radraw and the UX is something i could imaginate that, thus it could be a slight issue – Victor Feb 08 '22 at 13:47
  • 1
    Race conditions is always possible because there may be async code, and DOM-related code can be async either. With $q vs native promises, you'll likely be limited to race conditions caused by other native promises, not setTimeout, etc, that's because native promises are quite fast in JS event loop and primarily compete against each other. Given `let a = 1; Promise.resolve(2).then(v => a = v)`, `$q.resolve().then(() => console.log(a))` will result in `1`, and `Promise.resolve().then(() => console.log(a))` will result in `2` – Estus Flask Feb 08 '22 at 14:06
  • ok, you give some material to think about it! Thanks! – Victor Feb 08 '22 at 15:33
2

Is there an elegant way to override all angular-js and angular-material (also included) interfaces to use es6 promises

We just went with IPromise everywhere. Its difficult to replace IPromise with Promise due to underlying implementation differences. You would be better off doing Promise.resolve(someIPromise) if you want to but then it wouldn't play with angular.

basarat
  • 261,912
  • 58
  • 460
  • 511
  • Within the angular app, I am doing this. Where things get not intuitive is when we use external (non-angular specific) libraries that reference the es6 Promise Typescript interface. – Ken Jun 30 '16 at 14:16