2016-02-25 23 views
16

Nowa funkcja asynchronizacji/oczekiwania TypeScript wykorzystuje obietnice ES6. AngularJS korzysta z obietnic serwisowych o nieco innym interfejsie niż $q.

Czy istnieje sposób na użycie funkcji asynchronizacji/oczekiwania TypeScript z gwarancjami serwisowymi $q?

+1

Tak. Pierwszym problemem jest to, że muszę przekonwertować każdą odpowiedź obietnicy-odpowiedzi z usługi Ng, aby móc na nią czekać. Drugi problem polega na tym, że obietnice ES6 wygenerowane przez oczekiwane wyrażenie nie rozpoczynają cyklu skoku kątowego. – Random

Odpowiedz

16

Oto jak to zrobić:

angular.module('your app') 
     .run(['$window', '$q', function($window, $q) { 
      $window.Promise = $q; 
     }]); 
+0

Dziękuję, jest o wiele bardziej zgrabna niż moja wersja. Nie wiedziałem, że usługa $ q może być używana jako konstruktor zgodny z es6-obiecuje – Random

+1

To działa, i używam go już teraz w kilku projektach. Ale nie mogę powstrzymać się od wstrząśnięcia uczuciem, że to jest niegrzeczne. Zastąpienie globalnego obiektu Promise usługą Angular $ q wydaje się ... hackish. –

+2

Zastąpienie natywnej Promise $ q jest prawdopodobnie najgorszą rzeczą, jaką można zrobić dla aplikacji. Są to zasadniczo różne implementacje, które zachowują się inaczej, co zepsuje wszystkie kodki stron trzecich, które zależą od 'Obietnicy'. Oświadczenie o "hackish" $ window jest fałszywe - nie istnieje, ponieważ Angular nie jest w stanie użyć rodzimego okna, ale ponieważ DI jest dobre. – estus

3

Nie sądzę, że będziesz w stanie użyć ich bezpośrednio. Ale to powinno być dość łatwe do konwersji q obietnicę w obietnicy ++, coś takiego:

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

Problem polega na tym, że w tym przypadku muszę zawijać każdą usługę, która zwraca $ q obiecuje. Co więcej, obietnice ES6 nie inicjują cyklu skoku kątowego. Tak więc, w tym przypadku muszę nazwać '$ apply' po każdym' czekaj' – Random

1

końcu użyłem następujące rozwiązania:

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 dla maszynopis 1.8 generuje __awaiter funkcji w każdym pliku, w którym Używany jest operator await. Zamieniam go na implementację, która przekazuje niestandardowego konstruktora Promise, który inicjuje cykl podsumowania po każdym wywołaniu resolve i reject. Oto przykład użycia: https://github.com/llRandom/ts-awaiter

+0

Po prostu z ciekawości, w jaki sposób ten uchwyt odrzuca? złapać blok? – Luis

+0

Tak. Dodano przykład do repozytorium – Random

+0

Może to spowodować niepotrzebne trawienie, a trawienie jest najczęstszym wąskim gardłem dla wydajności aplikacji AngularJS. A rozwiązanie nie dotyczy docelowego TypeScript ES2017 ... natywny async/await już tam jest. – estus