2016-05-31 15 views
31

Cosa può ES6 Classes fornire, come un modello di organizzazione, al codice asincrono. Di seguito è riportato un esempio con ES7 async/await, una classe ES6 può avere un metodo asincrono o un costruttore in ES7?Le classi ES6 JavaScript sono di qualsiasi uso con basi di codice asincrone?

posso fare:

class Foo { 
    async constructor() { 
     let res = await getHTML(); 
     this.res = res 
    } 
} 

E, se non come dovrebbe un'opera costruttore che fa questo?

class Foo { 
    constructor() { 
     getHTML().then(function (res) { 
      this.res = res 
     } 
    } 
} 

Se nessuno di questi schemi di lavoro, un costruttore può (e classi Inoltre) in un ES6 class supportare qualsiasi forma di asincronia che opera su stato dell'oggetto? O sono solo per basi di codice puramente sincrone? Gli esempi di cui sopra sono nel costruttore, ma non hanno bisogno di essere .. Spingendo il problema giù un altro livello ..

class Foo { 
    myMethod() { 
     /* Can I do anything async here */ 
    } 
} 

Oppure, con un getter ...

class Foo { 
    get myProp() { 
     /* Is there any case that this is usefully asynchronous */ 
    } 
} 

Il solo degli esempi a cui potrei pensare è di eseguire qualcosa in parallelo all'interno dello stesso metodo/costruttore/getter, ma per risolvere il tutto prima della conclusione. Sono solo confuso perché sembra con tutta la spinta verso librerie completamente asincrone, questo serve solo a confondere le cose. Ad eccezione degli esempi da manuale, non riesco a trovare un'applicazione per la quale sono utile.

+0

si * potrebbe * restituire una promessa da parte del costruttore che si risolve con l'istanza dando così accesso all'istanza una volta inizializzata. –

+0

@KevinB mi è venuto in mente il pensiero, ma suona orribile. –

+0

Non mi piace particolarmente, ma ... quale altro modo ci sarebbe? deve esserci una richiamata da qualche parte, o sarà una promessa o una richiamata passata come parametro. async/await ha ancora un callback, semplicemente non lo vedi. –

risposta

27

posso fare async constructor()

No, questo è un errore di sintassi - proprio come constructor*(). Un costruttore è un metodo che non restituisce nulla (nessuna promessa, nessun generatore), inizializza solo l'istanza.

E, se non come dovrebbe un'opera costruttore che fa questo

Tale un costruttore non dovrebbe esistere affatto, vedere Is it bad practice to have a constructor function return a Promise?

Può ES6 classi supportano qualsiasi forma di asincronia che opera sullo stato dell'oggetto? O sono solo per basi di codice puramente sincrone?

Sì, è possibile utilizzare metodi asincroni (anche con la proposta di async sintassi) sulle classi, e getter può tornare promesse pure.

Tuttavia, sarà necessario decidere cosa deve accadere quando viene chiamato un metodo mentre un processo asincrono è ancora attivo. Se si desidera che esegua in sequenza tutte le operazioni, è necessario memorizzare lo stato dell'istanza all'interno di una promessa per la fine della sequenza su cui è possibile eseguire il collegamento. Oppure, se si desidera consentire operazioni parallele, l'approccio migliore consiste nel rendere le istanze immutabili e restituire una promessa per un'altra istanza.

+2

Questa è davvero una buona risposta, potrei modificarla per fornire un esempio di una classe che si incatena su se stessa attraverso le promesse. Non sono ancora soddisfatto che questa sia sempre una buona idea. Sembra più un anti-modello, ancora. –

+5

@ EvanCarroll: se è una buona idea dipende da cosa stai facendo. La sintassi 'class' di ES6 non porta nulla di nuovo sulla tabella, l'asincronia e lo stato negli oggetti (istanze) sono sempre stati complicati. – Bergi

3

Un altro modo in cui Classes può essere utile per organizzare attività asincrone è con l'uso esclusivo di static methods.

class Organizer { 
    static async foo() { 
     const data = await this.bar(); 
     data.key = value; 
     return data; 
    } 
    static async bar() { 
     return {foo:1, bar:2} 
    } 
}; 

Organizer.foo(); 

Naturalmente, questo non è diverso che creare un oggetto semplice letterale, o un nuovo file e includendolo, tranne che si può in modo più pulito extend esso.

+5

Non dovresti mai farlo. Basta usare un oggetto letterale (puoi estenderlo anche banalmente usando 'Object.create' e' Object.assign'). Oppure, dati i moduli ES6, usa solo più esportazioni con nome - estendere quelle è ancora più semplice, è come un'eredità parassitaria. – Bergi

4

ECMAScript 2017 è inteso come classi di metodi asincroni.

L'invocazione di un'altra funzione asincrona o promessa-promessa è una soluzione unica!

Il codice altamente espressiva legge senza piano interruzione fondo indipendentemente esecuzione differita

Se si dispone di callback, gestori di errori alternative, esecuzione parallela o altri bisogni insoddisfatti, istanziare promesse corpo della funzione. È meglio avere il codice nel corpo della funzione piuttosto che in un esecutore di promesse e notare che non esiste un codice di callback che tocchi il try-catch: fai il next-to-nothing lì.

Il metodo asincrono può restituire una promessa, un valore normale, o gettare

le API di callback che Node.JS chi è abituato ad amare, noi ora odio con una passione: tutti devono essere avvolti in promesse

La bellezza di async/attendono è che gli errori bolla implicitamente

class MyClass { 
    async doEverything() { 
    const sumOfItAll = await http.scrapeTheInternet() + 
     await new Promise((resolve, reject) => 
     http.asyncCallback((e, result) => !e ? resolve(result) : reject(e))) 
    return this.resp = sumOfItAll 
    } 
} 

Se limitato a ECMAScript 2015 e non asincrone, valori restituiti promessa:

class ES2015 { 
    fetch(url) { 
    return new Promise((resolve, reject) => 
     http.get(url, resolve).on('error', reject)) 
     .then(resp => this.resp = resp) // plain ECMAScript stores result 
     .catch(e => { // optional internal error handler 
     console.error(e.message) 
     throw e // if errors should propagate 
     }) 
    } 
} 

Questa versione di ECMAScript 2015 è ciò che si sta veramente chiedendo, qualsiasi comportamento desiderato può essere codificato utilizzando il costrutto della promessa restituita.

Se si vuole veramente eseguire promesse nel costruttore, è una buona idea passare le funzioni di cattura o fornire un costrutto di callback in modo che i consumatori possano agire in caso di adempimento o rifiuto della promessa. Nel costruttore, è anche buona norma aspettare nextTick/.then prima di fare un vero lavoro.

Ogni promessa ha bisogno di un fermo finale o ci saranno problemi

0

Questa è una risposta in ritardo, ma il motivo per il tuo secondo esempio non funziona è a causa di un errore di contesto. Quando si passa un function() {} come argomento a Promise.prototype.then(), il codice lessicale this all'interno della funzione sarà la funzione stessa e non la classe. Questo è il motivo per cui l'impostazione di this.res sembra non fare nulla: this, in tal caso, fa riferimento all'ambito di validità della funzione.

Ci sono diversi modi per accedere un ambito esterno in Javascript, quella classica (che si vede abbondantemente nel codice ES5) essere:

class Foo { 
    constructor() { 
    var _this = this 

    getHTML().then(function (res) { 
     _this.res = res 
    }) 
    } 
} 

Facendo un riferimento alla classe this, è possibile accedervi negli scopi interni.

Il modo ES6 di farlo è utilizzare arrow functions, che non crea un nuovo ambito, ma piuttosto "mantiene" quello corrente.

class Foo { 
    constructor() { 
    getHTML().then(res => this.res = res) 
    } 
} 

parte contesto preoccupazioni, questo non è ancora un modello asincrono ottimale, a mio parere, perché non hai modo di sapere quando getHTML() ha finito, o peggio, ha fallito. Questo problema è risolto elegantemente con async functions. Sebbene non sia possibile creare un async constructor() { ... }, è possibile avviare una promessa nel costruttore e await nelle funzioni che dipendono da esso.

Example gist di una proprietà asincrona in un costruttore di classi.

Problemi correlati