2015-05-17 6 views
13

Die Methode ECMAScript-6 iterator.throw(err) wird oft als eine Ausnahme injizierend beschrieben, als ob sie bei der yield-Anweisung im Generator aufgetreten wäre. Das Problem besteht darin, dass der Stapel-Trace für diese Ausnahme keinen Verweis auf die Datei/Zeile für die Yield-Anweisung oder sogar die Funktion, in der sie enthalten ist, enthält. Stattdessen wird der Stack-Trace nur generiert, wenn das Ausnahmeobjekt ist konstruiert, die nicht innerhalb des Generators ist.ES6-Generatoren: schlechte Stack-Ablaufverfolgung von iterator.throw (err)

Die Frage ist: Wie bekomme ich den Ort der beleidigenden Yield-Anweisung, in einem Stack-Trace oder sonst?

function* one_of_many_generators() { 
    // ... 
    yield ajax(url); // <-- what I need in the stack trace 
    // ... 
} 

function outer() { 
    var iterator = one_of_many_generators(); 
    iterator.next(); // runs to the first yield 

    // inject exception at the yield statement 
    iterator.throw(Error("error")); // <-- top of stack trace shows here 
} 

Obwohl dieses Problem nicht spezifisch für Promises ist, kann sie machen es einfacher, das Problem Bild. In meinem Fall verwende ich ein Task-System mit Generatoren und Versprechungen. Die hypothetische Funktion ajax() gibt ein Versprechen zurück, und wenn das abgelehnt wird, wird der Fehler mit diesem Mechanismus in einen throw bei der yield-Anweisung umgewandelt.

Die Stack-Traces im Debugger sind ziemlich nutzlos, weil ich keine Möglichkeit finde, die Funktion, Datei oder Zeilennummer für die Yield-Anweisung zu erhalten, wo diese Injektion stattfindet. Der Aufruf von iterator.throw(err) wird wie ein erneuter Durchlauf behandelt und erhält keine neuen Stapelinformationen. Daher wird nur eine Position innerhalb der ajax()-Funktion angezeigt, die von vielen Stellen aus aufgerufen werden kann, und durch einen neuen Fehler in outer() wie im obigen Beispiel Linien für alle Fehler werfen. Es gibt keinen Hinweis darauf, welche Generatorfunktion zum Debuggen des Fehlers ausgeführt wurde.

Ich verwende Chrome v42.

+1

Wenn Sie Bluebird verwenden, gibt es Promise.coroutine, die viele dieser Dinge für Sie erledigt. –

+1

Sie sollten einen Fehlerbericht/eine fehlende Funktion für Chrome melden, wenn Sie glauben, dass etwas fehlt. Es gibt nichts, was andere tun können. Ich würde vielleicht mehr solche Bugs in allen Browsern für alles ES6 erwarten. http://dev.chromium.org/for-testers/bug-reporting-guidelines –

+3

Stack-Traces in JavaScript sind immer an die von Ihnen erstellte "Error" -Instanz gebunden und werden immer in der Zeile angezeigt, in der sie erstellt wurden. Ihr Stack-Trace zeigt also immer die Zeile an, in der 'Error' aufgerufen wird. –

Antwort

0

Iteratoren und Versprechungen vermischen sich (noch) nicht sehr gut - Sie liefern im Wesentlichen ein Versprechen, das dann außerhalb der Schleife versagt.

Sie diese Runde, indem die Ergebnisse der Versprechen zurück zum Generator, so etwas wie bekommen: Nur

function* one_of_many_generators() { 
    // ... 
    var promiseResult = yield ajax(url); // <-- what I need in the stack trace 

    // Now we're back in the generator with the result of the promise 
    if(notHappyWithResult(promiseResult)) 
     throw new Error('Reason result is bad'); 
    // ... 
} 

async function outer() { 
    var iterator = one_of_many_generators(); 
    let prms = iterator.next(); // runs to the first yield 

    // Wait for the promise to finish 
    let result = await prms; 

    // Pass the result back to the generator 
    let whatever = iterator.next(result); 
} 

: Dies ist eine Art, was async und await ohnehin tun (diese Schlüsselwörter nur syntaktischer Zucker zu sein für einen Generator von Versprechen mit Ergebnissen zurück) und wenn Sie sie verwenden, wird eine regelmäßige try-catch funktionieren.

iterator.throw ist hauptsächlich eine Möglichkeit, die Iteration zu stoppen und keine Ausnahme zurückzusenden - der oberste Teil des Stapels ist immer noch dort, wo Sie die Error erstellen.

Schließlich in Kürze in Chrome sind async iterators - diese sind ziemlich mächtig und sind alle über Wiederholungen der Versprechen.