2015-10-20 23 views
5

ich Oboe.js bin mit einer wirklich, wirklich großen JSON-DateiUnhandle Versprechen Ablehnung in asynchronen Versprechen

const promises = []; 
oboe('http://domain/my-file.js') 
    .node('items.*', item => { 
    // parseItem() returns a rejected Promise because of invalid JSON items 
    promises.push(parseItem(item)); 
    }) 
    .done(() => { 
    Promise.all(promises).then(() => { 
     doSomething(); 
    }); 
    }) 

Aber mein Browser-Konsole wird mit Uncaught (in promise) überflutet zu analysieren. Das gleiche geschieht, wenn Sie ein Versprechen in einem setTimeout() wie

const promises = []; 
setTimeout(() => { 
    promises.push(Promise.reject()); 
}, 500); 
// some time in the future 
Promise.all(promises); 

schreibt Was ist wirklich seltsam: moderner Browser anders verhalten. In Firefox Developer Edition funktioniert alles ohne die Fehlermeldungen und in Chrome werde ich mit Uncaught (in promise) überflutet. In Chrome erhalten Sie die Nachricht sofort, wenn Sie Promise.reject(); ohne einen Haken schreiben. In Firefox und Safari passiert nichts.

Also, was ist die Lösung dafür? Ignorieren der Nachricht? Ich meine, wenn dieses Verhalten wirklich in der offiziellen Promise-Spezifikation ist, dann machen Versprechen in asynchronem Code für mich keinen Sinn.

+1

Es gibt derzeit zwei Lager von Menschen in Bezug auf ES6 verspricht. Ein Camp (inklusive Chrome-Devs) ist der Ansicht, dass die Art, wie Sie es verwenden, ein Missbrauch ist. Das Verhalten, das Sie erleben, ist nicht in der Spezifikation für Versprechungen, obwohl es mehrere Vorschläge dafür gibt, weil das andere Lager immer wieder sagt, dass Anwendungsfälle wie Ihre relevant sind. Leider, einige der Browser hinzugefügt unbehandelt Versprechen Ablehnung Protokollierung trotz der Mangel an Spezifikationen und trotz des Push-Back dagegen. –

+0

@MicahZoltu um fair zu sein, sind die Camps sogar unter Chrome-Devs aufgeteilt. –

+0

@MicahZoltu danke für die Klarstellung. Im Moment ist es wirklich verwirrend, welche Implementierung die richtige ist. – LongFlick

Antwort

2

Ihr Oboe-Problem basiert auf der Tatsache, dass Oboe JSON streamt, so dass wir nie im Voraus wissen, wie viele Versprechen es gibt, so dass wir die Verantwortung nicht vorab an Promise.all anhängen können. Wir können Oboe verheißen, um Versprechen in seinen Methoden zurückgeben zu können.

Normalerweise würde ich RxJS verwenden, um automatisch einen Stream vom Ereignisemitter zu erstellen - und die Methoden von RxJS können bereits Versprechungen zurückgeben und sie dann aggregieren. Allerdings - da ich nicht einen Dritten Bibliothek hier will, und es hat weniger Lehrwert - lass es sie implementieren:

function addMap(oboe) { 
    oboe.map = function(selector, mapper){ 
    var promises = []; 
    return new Promise(function(resolve, reject){ // create a new promise 
     oboe.node(selector, function(match){ 
     var result = mapper(match); // get result 
     // signal that we're handling the rejection to make sure it's not handled. 
     result.catch(function(){}); 
     promises.push(result); 
     }); 
     oboe.fail(reject); 
     oboe.done(function(){ resolve(promises); }); 
    }); 
    }; 
} 

Welche uns tun lassen würde:

var o = oboe("foo"); 
addMap(o); 
o.map("items.*", item => downloadItem(item)).then(result => { 
    // handle result here 
}); 

Ihr setTimeout Problem ist sehr erfunden. Die überwiegende Mehrheit der Menschen schreibt keinen Code, der in der Praxis so aussieht - in der Praxis ist das Hinzufügen eines Fehlerhandlers asynchron ein ziemlich seltener Anwendungsfall, wenn er nicht gegen eine API arbeitet, die Sie dazu zwingt (wie das Beispiel Oboe.js).

Was ist wirklich seltsam: moderne Browser verhalten sich anders

Dies liegt daran, Firefox GC verwendet für Ablehnungen und Chrome einen Timer Erkennung nicht behandelte. Es ist das Implementierungsdetail - die einzige Garantie, die Sie haben werden, ist, dass Fehler nicht protokolliert werden, wenn sie innerhalb einer Mikrotask (synchron oder in einem then, der in derselben Runde ausgeführt wird) angehängt werden.

+0

Vielen Dank für das Beispiel. Sie können es auf alle Callback-basierten APIs wie in Node.js oder eine einfache AJAX-Anfrage übertragen: Wenn Sie eine Callback-basierte API mit einem Versprechen umschließen und dieser Callback in der Zukunft aufgerufen wird, müssen Sie das Versprechen ablehnen habe das gleiche Problem. In meinem Fall verpacke ich Oboe mit einem Versprechen und rufe eine zweite Callback-basierte API auf und verpacke diese auch in ein Versprechen. Mein zweites Versprechen wird abgelehnt und dann bekomme ich den Fehler oben.Also, was ist die Lösung dafür? Leider bin ich im StackOverflow Kommentar System sehr eingeschränkt, so dass ich hier nicht viel schreiben kann. – LongFlick

+0

Oder: Ich kann keine Versprechen verwenden, die irgendwann in der Zukunft abgelehnt werden und mit Promise.all() behandelt werden. Das Hauptproblem hier ist, dass ich keinen direkten Haken() auf meinem Versprechen habe, aber deshalb in meinem Promise.all() Anruf. Wenn ich den Haken() an meinem inneren Versprechen mache, funktioniert es, aber das will ich nicht. Ich möchte es in Promise.all() fangen. Ich glaube, ich verstehe es nicht. Also, was ist die Lösung für APIs, wo ich verspricht, dass Aufrufe APIs, die auch Versprechen sind, aber keine Catch() - Handler. Sollten sie alle catch() Handler haben? Ich dachte, dass Promise.all(). Catch() genau das ist, was ich suche – LongFlick

+0

@LongFlick 'var p = Promise.reject(); p.catch (() => {});/* Anmerkung, wir haben p nicht geändert, es ist das gleiche Versprechen, wir haben gerade einen catch-Handler * /; p.then (...);/* kein unbehandelter Ablehnungsbericht mehr, wir haben ausdrücklich keine Angabe gemacht */' –