2016-01-12 16 views
7

Staram się lepiej zrozumieć, co jest w języku JavaScript technicznie możliwe pod async function, nawet jeśli w zasadzie wiem, jak z nich korzystać.techniczna różnica między asynchroniczną funkcją ES7 a obietnicą?

Wiele wstępy do async/czekają uczynić uwierzyć, że funkcja async jest w zasadzie tylko obietnica, ale to oczywiście nie jest (przynajmniej nie z Babel6-transpiled code):

async function asyncFunc() { 
    // nop 
} 

var fooPromise = new Promise(r => setTimeout(r, 1)); 

console.clear(); 

console.log("typeof asyncFunc is", typeof asyncFunc); // function 
console.log("typeof asyncFunc.next is", typeof asyncFunc.next); // undefined 
console.log("typeof asyncFunc.then is", typeof asyncFunc.then); // undefined 

console.log("typeof fooPromise is", typeof fooPromise); // object 
console.log("typeof fooPromise.next is", typeof fooPromise.next); // undefined 
console.log("typeof fooPromise.then is", typeof fooPromise.then); // function 

Mimo to, jest to z pewnością możliwe na await obietnicę, jak await fooPromise().

  • Czy async funtion rzeczą na jego własny i await jest po prostu kompatybilny z obietnic?

  • i czy istnieje sposób na rozróżnienie między prostymi function i async function w czasie wykonywania (w sposób zgodny z Babel)?

Odpowiedz

9

Funkcja asynchroniczny jest funkcja, która zwraca obietnicę. To pomaga w przypadkach, gdy masz kilka działań asynchronicznych dzieje się jedna po drugiej:

function asyncFunc() { 
    return doSomethingAsync() // doSomethingAsync() returns a promise 
    .then(() => { 
     // do some stuff 
     return doSomethingElseAsync(); // returns a promise 
    }) 
    .then(something => { 
     // do some stuff 
     return doSomethingElseEntirelyAsync(something); // returns a promise 
    }); 
} 

Okazuje się

async function asyncFunc() { 
    await doSomethingAsync(); // awaits for a promise 
    // do some stuff 
    let something = await doSomethingElseAsync(); // awaits for a promise 
    // do some stuff 
    return doSomethingElseEntirelyAsync(something); // returns the final promise 
    // Note that even if you return a value, like return 5, the function as a whole 
    // still returns a promise! 
} 

to brzmi dużo lepiej, i można użyć zwykłych narzędzi, takich jak próby/catch i pętle do pracy z nimi, nawet jeśli są asynchroniczne.

Funkcje asynchroniczne zastępują obietnice, są na nich cukrem, aby poradzić sobie z konkretnymi przypadkami, w których występuje wiele sekwencyjnych akcji asynchronicznych.

Ponieważ await jest w zasadzie tylko „czekają na tej obietnicy”, nadal można korzystać z ciekawych metod agregacji jak Promise.all() i Promise.race() i czekają na wynik kilku (lub pierwszy z kilku) obietnicach.

Nie jestem zaznajomiony ze sposobem rozróżniania tych dwóch w czasie wykonywania, ponieważ podobnie jak klasy, funkcje asynchroniczne są po prostu cukrem na Obietnicach. (Chociaż mogą istnieć hacki, takie jak używanie funkcji .toString i analizowanie wyników, nie liczę tych wyników).

+0

Dzięki, ma to wiele sensu. Zasadniczo, 'asyncFunc' nie jest obietnicą, ale' asyncFunc() 'jest - lub innymi słowami:' typeof asyncFunc(). Then == "function" ' –

+0

To jest dokładnie poprawne. –

0

Para async/await to mechanizm, który pozwala pisać kod asynchroniczny w stylu synchronicznym iw mojej skromnej opinii jest to najprostsza i czytelna składnia, jak dotąd, aby poradzić sobie z kodem asynchronicznym (patrz także this article). Siła składni w rzeczywistości działa tak, jak działa await. Ale aby użyć funkcji await w ciele funkcji, funkcja musi być poprzedzona prefiksem async.

Jeśli potrzebujesz więcej informacji, jest spec for async/await here.

Obecna implementacja w Babel 5 oparta jest na https://github.com/facebook/regenerator.Jak widać w transpiled code funkcja jest kompilowany do:

function asyncFunc(which, one, two) { 
    return regeneratorRuntime.async(function asyncFuncMaybe$(context$1$0) { 
... 

Jeśli kopać w babel-regenerator-runtime pakietu Babla znaleźć kod Facebooka. Na line 205 znaleźć:

// Note that simple async functions are implemented on top of 
// AsyncIterator objects; they just return a Promise for the value of 
// the final result produced by the iterator. 
runtime.async = function(innerFn, outerFn, self, tryLocsList) { 
... 

W celu transpile do ES5 Babel potrzeb async/await zrobić, aby zmienić kod, dzięki czemu możemy śledzić, gdzie jesteśmy w trakcie wykonywania funkcji i AsyncIterator jest obiektem, który śledzić tego stanu.

Babel 6 oferuje więcej opcji i pozwala wybrać implementację, której chcesz użyć. Zobacz Transpile Async Await proposal with Babel.js?

Więc dotyczące pytania:

  • async/await są zarówno coś na jego rękę. Według specyfikacji, muszą działać z obietnicami. W szczególności możesz obiecać na await, a po uruchomieniu funkcji async zwróci ci to obietnicę.
  • Ponieważ funkcja async jest transpiled do funkcji, która zwraca obietnicę, nie istnieje prosty sposób na odróżnienie jej od funkcji nie asynchronicznej, która zwraca obietnicę. Twój numer fooPromise powinien wyglądać bardziej jak var fooPromiseFunc = function() {return new Promise(r => setTimeout(r, 1))};, który uniemożliwia odróżnienie od czarnego pudełka od fooPromiseFunc i asyncFunc. Oba funkcje zwracają obietnicę. Jaki jest powód, dla którego chcesz odróżnić funkcję async i nie asynchroniczną w czasie wykonywania? W praktyce można ich używać w ten sam sposób, więc nie rozumiem, dlaczego trzeba je inaczej traktować. Do celów debugowania, jeśli naprawdę potrzebujesz dowiedzieć się, czy funkcja jest zdefiniowana async, w Babel 5 możesz użyć czegoś takiego jak (asyncFunc+"").indexOf('regeneratorRuntime.async') > 0 lub dokładniejszego wyrażenia regularnego. Ale to naprawdę jest hacky i nie użyłbym go w kontekście poza debugowaniem lub studiowaniem.
+0

Dzięki za szczegółowe wyjaśnienie. Odp: * z jakiego powodu chcesz rozróżniać funkcję asynchroniczną i nie asynchroniczną w środowisku wykonawczym? *: Faktycznie chciałem tylko odróżnić normalne callbacki od obietnic (w końcu, aby uczynić wyrażenie "ekspresowe"/kompatybilne z asynchronicznym w automatyczny sposób). Teraz, gdy wiem, jak działają, wszystko jest dla mnie jasne i faktycznie udało mi się stworzyć idealnie działającą (eksperymentalną) łatkę dla 'express'. –

+0

Do tego mogą ci się przydać te 2 linki: https://strongloop.com/strongblog/async-error-handling-expressjs-es7-promises-generators/ oraz https://github.com/luin/express-promise –

+0

Dzięki za te linki. Znałem je już przed opublikowaniem tego pytania i za pomocą odpowiedzi znalazłem sposób na uniknięcie użycia jawnej funkcji wrappera i nadal otrzymuję dokładnie taki sam wynik. –

Powiązane problemy