Frage

Ich lese dieser Artikel und der Abschnitt auf dem Versprechen Abstraktion scheint ein wenig zu mir zu kompliziert. Im Folgenden wird als ein Beispiel gegeben:

requestSomeData("http://example.com/foo") // returns a promise for the response
    .then(function(response){ // ‘then’ is used to provide a promise handler
        return JSON.parse(response.body); // parse the body
    }) // returns a promise for the parsed body
    .then(function(data){
        return data.price; // get the price
    }) // returns a promise for the price
    .then(function(price){ // print out the price when it is fulfilled
        print("The price is " + price);
    });

Es scheint mir, dass die folgenden das gleiche Ergebnis mit weniger Codezeilen bieten könnte:

requestSomeData("http://example.com/foo")
    .requestHandler(function(response){
        // parse the body
        var data  = JSON.parse(response.body);

        // get the price
        var price = data.price;

        // print out the price
        print("The price is " + price);
    });
War es hilfreich?

Lösung

Während es wahr ist, dass beide letztlich das Gleiche erreichen, ist der Unterschied, dass Ihr zweites Beispiel nicht asynchron ist. Betrachten wir zum Beispiel, was passiert, wenn JSON.parse(...) eine extrem teure Operation erweist; Sie werden bis alles fertig ist zu hängen haben, was nicht immer sein kann, was Sie wollen.

Das ist, was verspricht man bekommt: die mächtige Fähigkeit, die Berechnung der richtigen Antwort, bis eine bequemere Zeit zu verschieben. Wie der Name der Konstrukt „Versprechen“ schon sagt, Sie irgendwann das Ergebnis zu geben, nur nicht unbedingt jetzt. Sie können mehr über Futures und verspricht Arbeit in einem größeren Maßstab lesen hier .

Andere Tipps

Lassen Sie uns vergleichen das Versprechen Beispiel zu einem reinen Javascript Beispiel:

// First we need a convenience function for W3C's fiddly XMLHttpRequest.
// It works a little differently from the promise framework.  Instead of 
// returning a promise to which we can attach a handler later with .then(),
// the function accepts the handler function as an argument named 'callback'.

function requestSomeDataAndCall(url, callback) {
    var req = new XMLHttpRequest();
    req.onreadystatechange = resHandler;
    req.open("GET", url, false);
    req.send();
    function resHandler() {
        if (this.readyState==4 && this.status==200) {
            callback(this);
        } else {
            // todo: Handle error.
        }
    }
}

requestSomeDataAndCall("http://example.com/foo", function(res){
    setTimeout(function(){
        var data = JSON.parse(res.responseText);
        setTimeout(function(){
            var price = data.price;
            setTimeout(function(){
                print("The price is "+price);
            },10);
        },10);
    },10);
});

Wie Norbert Hartl wies darauf hin, JSON.parse () wird der Browser für große Saiten hängen. Also ich setTimeout () verwendet, um seine Ausführung zu verzögern (nach einer Pause von 10 Millisekunden). Dies ist ein Beispiel für Kris Kowal-Lösung. Es erlaubt den aktuellen Javascript Thread vollständig, um den Browser zu präsentieren DOM Änderungen zu befreien und scrollen Sie die Seite für den Benutzer, bevor der Rückruf ausgeführt wird.

Ich hoffe, die Commonjs versprechen Rahmen auch so etwas wie SetTimeout verwendet, da sonst die späten Versprechen in dem Beispiel des Artikels tatsächlich synchron laufen werden wie befürchtet.

Meine Alternative oben sieht ziemlich hässlich, mit den späteren Prozessen weitere Vertiefung erfordern. Ich umstrukturiert den Code, so dass wir unsere Prozesskette können alle in einer Ebene:

function makeResolver(chain) {
    function climbChain(input) {
        var fn = chain.shift();      // This particular implementation
        setTimeout(function(){       // alters the chain array.
            var output = fn(input);
            if (chain.length>0) {
                climbChain(output);
            }
        },10);
    }
    return climbChain;
}

var processChain = [
    function(response){
        return JSON.parse(response.body);
    },
    function(data){
        return data.price; // get the price
    },
    function(price){
      print("The price is " + price);
    }
];

var climber = makeResolver(promiseChain);
requestSomeDataAndCall("http://example.com/foo", climber);

Ich hatte gehofft, dass zu demonstrieren traditionelle vorausÜberGang Rückrufe in Javascript ziemlich entspricht verspricht. Doch nach zwei Versuchen erscheinen ich mit Bezug auf die Reinlichkeit des Codes in dem ursprünglichen Beispiel gezeigt, haben, dass verspricht eine wesentlich elegantere Lösung ist!

Der zweite Code-Schnipsel zu Denial-of-Service-Angriff anfällig, weil example.com/foo nur ungültig json den Server zum Absturz zurückkehren kann. Auch leere Antwort ist ungültig JSON (obwohl gültig JS). Es ist wie mysql_* Beispiele mit grell SQL-Injection-Löchern.

Und das Versprechen Code kann viel als auch verbessert werden. Diese sind gleich:

requestSomeData("http://example.com/foo") // returns a promise for the response
    .then(function(response){ // ‘then’ is used to provide a promise handler
        // parse the body
        var data  = JSON.parse(response.body);

        // get the price
        var price = data.price;

        // print out the price
        print("The price is " + price);
    });

Und:

requestSomeData("http://example.com/foo")
    .requestHandler(function(response){
        try {
            var data = JSON.parse(response.body);
        }
        catch(e) {
            return;
        }

        // get the price
        var price = data.price;

        // print out the price
        print("The price is " + price);
    });

Wenn wir den Fehler behandeln wollte, dann würde diese gleich:

requestSomeData("http://example.com/foo") // returns a promise for the response
    .then(function(response){ // ‘then’ is used to provide a promise handler
        // parse the body
        var data  = JSON.parse(response.body);

        // get the price
        var price = data.price;

        // print out the price
        print("The price is " + price);
    }).catch(SyntaxError, function(e) {
        console.error(e);
    });

und

requestSomeData("http://example.com/foo")
    .requestHandler(function(response){
        try {
            var data = JSON.parse(response.body);
        }
        catch(e) {
            //If the above had a typo like `respons.body`
            //then without this check the ReferenceError would be swallowed
            //so this check is kept to have as close equality as possible with
            //the promise code
            if(e instanceof SyntaxError) {
                console.error(e);
                return;
            }
            else {
                throw e;
            }
        }

        // get the price
        var price = data.price;

        // print out the price
        print("The price is " + price);
    });

Man könnte auch hinzufügen, dass der Vorteil der ersten Version über das zweite ist, dass es verschiedene Operationen in der Verfeinerung Kette trennt (die Funktionen müssen entweder an Ort und Stelle nicht geschrieben werden). Die zweite Version mischt sowohl die Low-Level-Analyse mit Anwendungslogik. Insbesondere die SOLID Prinzipien als Richtlinien verwendet wird, verstößt gegen die zweite Version sowohl OCP und SRP .

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top