Domanda

Sto leggendo questo articolo la sezione della promessa di astrazione sembra un po ' troppo complicato per me.Il seguente è dato come esempio:

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);
    });

Mi sembra che la segue potrebbe ottenere lo stesso risultato con meno righe di codice:

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);
    });
È stato utile?

Soluzione

Mentre è vero che i due sarà, infine, ottenere la stessa cosa, la differenza è che il secondo esempio non è asincrona.Per esempio, consideriamo cosa succede se JSON.parse(...) risulta essere estremamente costoso operazione;dovrete appendere fino a quando tutto è finito, che non può essere sempre quello che vuoi.

È quello che promette di ottenere:la potente capacità di rinviare il calcolo della risposta giusta fino a un momento più conveniente.Come suggerisce il nome, il costrutto di "promesse" per darvi il risultato ad un certo punto, solo che non necessariamente subito.Si può leggere di più su futures e promette di lavorare su larga scala qui.

Altri suggerimenti

Mettiamo a confronto l'esempio promessa di un puro esempio Javascript:

// 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);
});

Come Norbert Hartl ha sottolineato, JSON.parse () si bloccherà il browser per stringhe di grandi dimensioni. Così ho usato setTimeout () per ritardare l'esecuzione (dopo una pausa di 10 millisecondi). Questo è un esempio di soluzione di Kris Kowal. Permette la corrente filo Javascript per completare, liberando il browser per presentare modifiche DOM e scorrere la pagina per l'utente, prima dell'esecuzione di callback.

Spero che i commonjs promettono quadro inoltre usa qualcosa come setTimeout, altrimenti le promesse più tardi nel l'esempio del articolo sarà davvero funzionare in modo sincrono come temuto.

La mia alternativa sopra sembra piuttosto brutto, con i processi successivi che richiedono un ulteriore rientro. Ho ristrutturato il codice, in modo da poter fornire la nostra catena di processo tutto in un unico livello:

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);

speravo di dimostrare che tradizionale previsionali passaggio di callback in JavaScript è più o meno equivalente a promesse. Tuttavia, dopo due tentativi mi sembra di aver dimostrato, con riferimento alla pulizia del codice dell'esempio originale, che le promesse sono di gran lunga più elegante soluzione!

Il secondo frammento è vulnerabile ad attacco denial of service perché example.com/foo può semplicemente restituire JSON valido per far crashare il server. Anche risposta vuota è JSON valido (anche se valide JS). E 'come esempi mysql_* con fori di iniezione SQL evidenti.

E il codice promessa può essere migliorata molto pure. Questi sono uguali:

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);
    });

E

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);
    });

Se volessimo gestire l'errore, allora questi sarebbe uguale:

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);
    });

e

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);
    });

Si potrebbe anche aggiungere che il vantaggio della prima versione sopra la seconda è che separa diverse operazioni della catena di affinamento (le funzioni non devono essere scritti sul posto o). La seconda versione mescola sia il parsing di basso livello con logica dell'applicazione. In particolare, utilizzando i solidi principi come linee guida, la seconda versione viola sia OCP e SRP.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top