2016-01-12 10 views
7

Sto cercando di capire meglio cosa sia tecnicamente un async function in JavaScript, anche se fondamentalmente so come usarli.differenza tecnica tra la funzione asincrona di ES7 e una promessa?

Molte introduzioni a asincrone/attendono di fare belive che una funzione async è fondamentalmente solo una promessa, ma che, ovviamente, non è il caso (almeno non con 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 

Ancora, è sicuramente possibile per await una promessa, come await fooPromise().

  • È un async funtion una cosa a sé stante e await è semplicemente compatibili con promesse?

  • e, c'è un modo per distinguere tra un semplice function e uno async function in fase di esecuzione (in un modo compatibile con Babel)?

risposta

9

Una funzione asincrona è una funzione che restituisce una promessa. Ti aiuta con i casi in cui si ha un gruppo di azioni asincrone accadendo uno dopo l'altro:

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 
    }); 
} 

si rivolge a

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! 
} 

Si legge molto meglio, e si può utilizzare gli strumenti normali come provare/catch e for loops per lavorare con loro, anche se sono asincroni.

Le funzioni asincrone sono NON un sostituto per le promesse, sono zucchero su di esse, per gestire casi specifici in cui si hanno molte azioni asincrone sequenziali.

Perché await è fondamentalmente solo "attendere per questa promessa", è comunque possibile utilizzare i metodi di aggregazione fresco come Promise.all() e Promise.race() e attendono per il risultato di diversi (o il primo di una serie) promesse.

Non ho familiarità con un modo di distinguere i due in runtime perché, come le classi, le funzioni asincrone sono solo zucchero sopra Promises. (Anche se potrebbero esserci degli hack come usare la funzione .toString e analizzare i risultati, non li conteggio).

+0

Grazie, ha molto senso. Quindi, in sostanza, 'asyncFunc' non è una Promessa, ma' asyncFunc() 'è - o con altre parole:' typeof asyncFunc(). Then == "function" ' –

+0

Che è esattamente corretto. –

0

La coppia async/await sono un meccanismo che permette di scrivere codice asincrono in uno stile sincrona e, a mio modesto parere è la sintassi più semplice e leggibile finora a che fare con il codice asincrono (vedi anche this article). La potenza della sintassi sta proprio nel modo in cui funziona lo await. Ma per utilizzare await all'interno del corpo di una funzione, la funzione deve essere preceduta da async.

Se avete bisogno di ulteriori informazioni c'è un spec for async/await here.

L'attuale implementazione in Babel 5 è basata su https://github.com/facebook/regenerator.Come si può vedere nel transpiled code la funzione viene compilata a:

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

Se si scava nel pacchetto di Babel babel-regenerator-runtime a trovare il codice di Facebook. A line 205 a trovare:

// 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) { 
... 

Per transpile per ES5 le async/await esigenze Babel fare per riorganizzare il codice in modo da poter tenere traccia dove ci troviamo durante l'esecuzione della funzione e il AsyncIterator è l'oggetto che tiene traccia di quello stato.

Babel 6 offre più opzioni e consente di scegliere l'implementazione che si desidera utilizzare. Vedi Transpile Async Await proposal with Babel.js?

Quindi per quanto riguarda le vostre domande:

  • async/await sono entrambi una cosa a sé stante. Secondo le specifiche, devono lavorare con promesse. In particolare, è possibile impostare await su una promessa e quando si esegue una funzione async, verrà restituita una promessa.
  • Poiché una funzione async è transpiled per funzionare che restituisce una promessa, non esiste un modo semplice per distinguerla da una funzione no-async che restituisce una promessa. Il tuo fooPromise dovrebbe essere più simile a var fooPromiseFunc = function() {return new Promise(r => setTimeout(r, 1))}; che rende fooPromiseFunc e asyncFunc indistinguibile da un potenziale casella nera. Sono entrambe funzioni che restituiscono una promessa. Qual è il motivo per cui si desidera distinguere una funzione async e nessuna-async in fase di runtime? In pratica possono essere utilizzati allo stesso modo, quindi non vedo perché dovrai minacciarli in modo diverso. A scopo di debug se hai davvero bisogno di scoprire se una funzione è definita async, in Babel 5 potresti usare qualcosa come (asyncFunc+"").indexOf('regeneratorRuntime.async') > 0 o un'espressione regolare più accurata. Ma quello è davvero l'hacker e non lo userei in un contesto esterno al debug o allo studio.
+0

Grazie per la spiegazione approfondita. Ri: * qual è il motivo per cui vuoi distinguere una funzione asincrona e non-asincrona in runtime? *: In realtà volevo solo distinguere i normali callback da Promises (alla fine per rendere 'express' Promise/async-compatible in un modo automatico). Ora che so come funzionano le cose per me è tutto chiaro e in realtà sono riuscito a creare una patch (sperimentale) perfettamente funzionante per 'express'. –

+0

Per questo è possibile trovare questi 2 collegamenti utili: https://strongloop.com/strongblog/async-error-handling-expressjs-es7-promises-generators/ e https://github.com/luin/express-promise –

+0

Grazie per questi link. Li conoscevo già prima di pubblicare questa domanda e con l'aiuto delle risposte ho trovato un modo per evitare l'uso di una funzione wrapper esplicita e ottenere comunque esattamente lo stesso risultato. –

Problemi correlati