2016-03-23 3 views
2

Ich habe einige JavaSript Code, der ein bestehendes Versprechen nimmt (zum Beispiel das Versprechen zurück durch holen()) und einen Mehrwert (sagen wir, dann/catch Hörer für das Debuggen, oder vielleicht mehr):Nach dem Hinzufügen eines Zuhörers zu einem Versprechen, sollte ich das ursprüngliche Versprechen oder das neue Versprechen verwenden?

let myFetch = function(url) { 
    return fetch(url).then(function(value) { 
    console.log("fetch succeeded: value=",value); 
    return value; 
    }.catch(function(reason) { 
    console.log("fetch failed: reason=",reason); 
    throw reason; 
    }); 
}; 

ich fand mich den obigen Code zu modifizieren, so dass die Zuhörer nur hinzugefügt werden, wenn eine bestimmte Bedingung erfüllt ist:

let myFetch = function(url) { 
    let promise = fetch(url); 
    if (some condition) { 
    promise = promise.then(function(value) { 
     console.log("fetch succeeded: value=",value); 
     return value; 
    }.catch(function(reason) { 
     console.log("fetch failed: reason=",reason); 
     throw reason; 
    }); 
    } 
    return promise; 
}; 

Jetzt frage ich mich, ist es wirklich sinnvoll für myFetch das neue Versprechen zurückgeführt, indem zurückzukehren „dann“ (eigentlich fangen, die Abkürzung für anot ist ihr "dann") wie oben, oder würde es mehr Sinn machen, das ursprüngliche Versprechen (mit den hinzugefügten Zuhörern) zurückzugeben? Mit anderen Worten, ich denke, das zweite „Versprechen =“ wegzulassen, so dass der Code wie dieser Stelle aussehen:

let myFetch = function(url) { 
    let promise = fetch(url); 
    if (some condition) { 
    promise.then(function(value) { 
     console.log("fetch succeeded: value=",value); 
     return value; 
    }.catch(function(reason) { 
     console.log("fetch failed: reason=",reason); 
     throw reason; 
    }); 
    } 
    return promise; 
}; 

Ist das effektiv unterscheidet sich von der vorherigen Version? Ist eine der beiden Versionen vorzuziehen, und wenn ja, warum?

+0

mögliche Duplikate von [Kann ich ein Versprechen schießen und vergessen?] (Http://StackOverflow.com/q/32384449/1048572) (die async verwendet/erwarten, aber das Problem ist das gleiche). – Bergi

Antwort

1

Wenn Ihr einziger Anwendungsfall ist, einfach etwas einzuloggen dann/fangen - es sollte nicht wichtig sein, solange alles gut geht. Dinge werden mehr durcheinander gebracht, wenn Sie eine Ausnahme bekommen. Betrachten Sie diese zwei Beispiele:

Return Urverheißung

function myFetch() { 
    let promise = new Promise(function (resolve, reject) { 
     resolve(100); 
    }); 
    promise.then(function() { throw new Error('x'); }); 
    return promise; 
} 

myFetch().then(function() { 
    console.log('success!'); 
}).catch(function (e) { 
    console.error('error!', e) 
}); 

Das Ergebnis ist success und der Fehler in der inneren then geworfen könnte in einigen Versprechen Bibliotheken erhalten geschluckt (obwohl die beliebtesten wie Drossel damit umgehen und Sie erhalten zusätzlichen Fehler Unhandled rejection Error: x). Der Fehler kann auch verschluckt werden, wenn native Promises in some environments verwendet wird.

Returning Versprechen

modifizierte
function myFetch() { 
    let promise = new Promise(function (resolve, reject) { 
     resolve(100); 
    }); 
    promise = promise.then(function() { throw new Error('x'); }); 
    return promise; 
} 

myFetch().then(function() { 
    console.log('success!'); 
}).catch(function (e) { 
    console.error('error!', e) 
}); 

Nun ist das Ergebnis error! Error: x.

+1

In diesem Fall wurde OP in beiden Fällen erfolgreich/fehlgeschlagen weitergeleitet und die einzige Funktion, die sie verwendet, wird jedoch nie ausgelöst. Schön, dich übrigens wieder zu sehen :) –

+1

@BenjaminGruenbaum Nun ... es wirft, wenn ich etwas Dummes wie Aufruf von console.warning() machte, wenn ich console.warn() meinte, nicht dass ich das jemals machen würde ;-) Im Allgemeinen lässt mich die Möglichkeit einer Wurfsituation, die ich nicht vorhergesehen habe, denken, dass es vielleicht besser ist, die "Returning Modified Promise" Version zu verwenden, damit unerwartete Dinge nicht verschluckt werden; Was denken Sie? –

+0

Das mit jeder anständigen Bibliothek unerwartete Dinge nicht sowieso geschluckt werden - einschließlich, aber nicht beschränkt auf native Versprechen (mit der unhandledRejection Ereignis), Bluebird, Q und anderen Bibliotheken. –

2

Nun, wenn Ihr Erfolgs-Handler return s der Wert und Ihr Ablehnungshandler throw s der Fehler ist - dann ist es im Grunde die Identitätstransformation für das Versprechen.

Nicht nur brauchen Sie nicht zu tun, dass promise = promise.then Sie haben nicht einmal die Werte zurückgeben müssen:

let myFetch = function(url) { 
    let promise = fetch(url); 
    if (some condition) { 
    promise.then(function(value) { 
     console.log("fetch succeeded: value=",value); 
    }.catch(function(reason) { 
     console.log("fetch failed: reason=",reason); 
    }); 
    } 
    return promise; 
}; 

Das heißt, wenn Sie ES6 verwenden und lassen, können Sie Pfeil-Funktionen verwenden, die macht das ein wenig schöner:

let myFetch = function(url) { 
    let promise = fetch(url); 
    if (some condition) { 
    promise.then(value => console.log("fetch succeeded: value=",value)) 
      .catch(reason => console.log("fetch failed: reason=",reason)); 
    } 
    return promise; 
}; 

Einige Versprechen Bibliotheken wie Bluebird bieten ein Tap-Dienstprogramm dafür. Das einzige Problem ist, dass, wenn jemals fetch Unterstützung für die Aufhebung von Versprechen hinzugefügt wird, Sie die Kette mit dem Handler if (some condition) brechen, wenn Sie es nicht verketten.

1

Sie sind Versprechen Verzweigung.Im zweiten Fall sind Verzweigung Sie effektiv die Versprechen Kette in zwei Versprechen Ketten, denn sobald ein Anrufer ruft myFetch:

myFetch("localhost").then(request => { /* use request */ }); 

dann promise wird .then es zweimal genannt hat (einmal in myFetch die Konsole zu tun Logging, und wieder hier).

Das ist in Ordnung. Sie können .then auf dem gleichen Versprechen so häufig aufrufen, wie Sie möchten, und die Funktionen werden zusammen in der gleichen Reihenfolge ausgeführt, wenn promise verrechnet wird.

Aber, wichtiger, jede Funktion stellt eine Abzweigung vom ursprünglichen Versprechen dar, unabhängig von jedem anderen Zweig. Das ist, warum Sie nichts nach Ihrer console.log zurückgeben oder wiederholen müssen: Niemand hört auf diesem Zweig zu, spezifisch ist der Anrufer von myFetch nicht betroffen.

Dies ist eine gute Passform IMHO für die Anmeldung, aber es gibt feine Timing und Fehlerbehandlung Unterschiede bewusst zu sein, wenn etwas zu tun mehr:

var log = msg => div.innerHTML += msg + "<br>"; 
 

 
var myFetch = url => { 
 
    var p = Promise.resolve({}); 
 
    p.then(() => log("a")).then(() => log("b")); 
 
    return p; 
 
} 
 

 
myFetch().then(() => log("1")).then(() => log("2")).catch(log); // a,1,b,2
<div id="div"></div>

Dieses emittiert a,1,b,2. Wie Sie sehen können, laufen hier zwei Ketten parallel vor. Es macht Sinn, wenn Sie darüber nachdenken, wenn promise gelöst ist, aber es kann überraschend sein.

Die andere Feinheit ist, dass Fehlerbehandlung auch pro Zweig ist (ein Zweig wird nie einen anderen). In der Tat hat der obige Code einen Fehler. Hast du es entdeckt? Es sollte einen catch nach .then(() => log("b")) geben, oder Fehler in allem, was Sie in diesem Zweig tun, enden unbehandelt oder verschluckt in einigen Umgebungen.

+1

Danke für diese Antwort und das exzellente subtile Beispiel zum Nachdenken. Musste zwischen ein paar guten Antworten wählen. –