2017-01-18 4 views
3

Ein großes Muster mit ES2017 async/await its:Elegant Handhabung Ablehnen auf `await`ed Javascript Versprechen

async function() { 
    try { 
    var result = await some_promised_value() 
    } catch (err) { 
    console.log(`This block would be processed in 
     a reject() callback with promise patterns 
     but this is far more intuitive`) 
    return false // or something less obtuse 
    } 
    result = do_something_to_result(result) 
    return result; 
} 

Lage zu sein, Fehler zu behandeln wie das ist wirklich schön. Aber sagen wir, dass ich asynchron einen Wert bekommen möchte, den ich vor einer Neuzuweisung schützen möchte (zB: eine Datenbanksitzung), aber ich möchte immer noch das async/await-Muster verwenden (nur weil ich denke, dass es viel intuitiver ist).

Das Folgende wird nicht funktionieren, weil konst Block scoped ist:

async function() { 
    try { 
    const result = await get_session() 
    } catch (err) { 
    console.log(`This block should catch any 
     instantiation errors.`) 
    return false 
    } 
    // Can't get at result here because it is block scoped. 
} 

Natürlich können Sie den Rest der Funktion innerhalb des try Block ausführen kann, aber dann laufen Sie Gefahr, Fehler erwischt zu werden, die fallen lassen sollte durch woanders. (Zum Beispiel habe ich diese Herausforderung gemacht, Tests zu schreiben, bei denen Fehler wie Testausfälle auf die Testsuite zurückfallen, aber selbst mit der Treiberinstanziierung umgehen wollten. Vielleicht falle ich hier in eine Art Anti-Pattern, indem ich diese Fehler nicht zurücklasse zur Testsuite.)

Die einfache Antwort offensichtlich ist, verwenden Sie dieses Muster hier nicht. Verwenden Sie stattdessen Versprechen und Rückrufe. Oder verwenden Sie eine var und vermeiden Sie Blockbereich const und let. Aber ich mag die Vorteile des Neuzuweisungsschutzes und blockiere den Umfang für andere Überlegungen.

[Frage]: Is there a way to wrap an await/async try/catch block to every function? Scheint eine mögliche Lösung zu sein, aber nicht so gut lesbar wie try/catch. Die Tatsache, dass try/catch den Funktionsumfang nicht unterbricht und ich return aus einem try/catch Block verwenden kann, scheint mir mehr im Einklang mit dem Geist von async/await zu sein, der asynchronerem Code eine prozedural anmutende Logik bringt.

Idealerweise möchten Sie etwas wie const x = await y() catch (err) oder const x = await y() || fail machen Aber ich kann nichts mit einem ähnlichen Ablauf denken, der syntaktisch korrekt ist.

UPDATE: wie von @ jmar777 unter einer anderen Alternative ist:

const x = await y().catch(() => {/*handle errors here*/}) 

das ist wahrscheinlich die nächste, die ich auf diese beiden Beispiele in der Praxis gefunden haben. Aber es bricht den Bereich return, der die Downstream-Ausführung in den obigen Beispielen blockiert. Was ist eine schöne synchrone Art der Handhabung von Dingen.

Jede Lösung hat ihre Kompromisse.

Ich habe gehisst manuell die Variablen mit let an der Spitze des Funktionsbausteins als Arbeitslösung noch eine interessante Frage (wie in jmar777 Antwort beschrieben), um die verschiedenen Ansätze zu sehen, so dass ich die Frage offen lassen jetzt.

+1

async/warte ist nicht Teil von ES7 (ES2016). Es wird Teil der diesjährigen Veröffentlichung ES2017 sein. –

Antwort

3

Möglicherweise haben Sie ein Missverständnis bezüglich der Vorteile der Verwendung von const. macht nicht, dass Wert unveränderlich mit einer const Deklaration einen Wert zuweisen, es bedeutet einfach, dass der Wert dieser Konstante kann nicht geändert werden oder neu deklariert:

Die const Deklaration Referenz eine schreibgeschützte erzeugt auf einen Wert . Es bedeutet nicht, dass der Wert, den es enthält, unveränderlich ist, nur dass der Variablenbezeichner nicht neu zugewiesen werden kann. Wenn der Inhalt beispielsweise ein Objekt ist, bedeutet dies, dass das Objekt selbst noch geändert werden kann.(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const)

In Ihrem Beispiel sind Sie wahrscheinlich am besten von Ihrer result Bindung außerhalb des try/catch manuell Hissen:

async function() { 
    let result; 

    try { 
    result = await get_session() 
    } catch (err) { 
    console.log(`This block should catch any 
     instantiation errors.`) 
    } 

    // do whatever else you need with result here... 
} 

Eine Alternative wäre, den Code zu restrukturieren, so dass Sie don Sie müssen sich auf einen Versuch/Fang überhaupt verlassen. Zum Beispiel:

async function() { 
    const result = await get_session().catch(someRejectionHandler); 

    // do whatever else you need with result here... 
} 

bewusst sein, nur, dass Ihr Downstream-Code, den Fall ordnungsgemäß behandeln muss, wo get_session() abgelehnt wurde, und result auf eine erfolgreiche Antwort nicht initialisiert basiert. Dies ist nicht anders als in Ihrem ersten Beispiel, aber vielleicht nicht ganz so offensichtlich beim Scannen des Codes.

+0

Ah, ich glaube, ich habe die Semantik von "unveränderlich" missverstanden und nicht, was "const" tut. Ich werde die Frage bearbeiten, um Verwirrung zu beseitigen. Auch innerhalb des ursprünglichen Codes, den ich geschrieben habe, hatte ich einen 'return' im' catch'-Block, um die Downstream-Ausführung zu verhindern. Ich werde den Pseudocode aktualisieren, damit er übereinstimmt. Die Fähigkeit, aus dem Inneren von 'catch' zurückzukehren, ist einer der Gründe, warum ich es vorziehe, mit einem Callback zu" catchen ", es scheint nur stilistischer im Einklang mit' async/await' zu sein. Ihre Hublösung ist diejenige, mit der ich den Code funktionierte. Es wäre schön, trotzdem const zu haben. –

+0

brauchst du nicht eine return-aussage in deinem versuch? – PositiveGuy

+0

@PositiveGuy am wahrscheinlichsten. Die Fehlerbehandlungslogik war nicht das Thema der Frage, also ist das wirklich nur ein Versuch/Fang-Stub, um das manuelle Hochziehen von "Ergebnis" auf einen höheren Bereich zu demonstrieren. – jmar777

Verwandte Themen