Pregunta

Estoy leyendo este artículo y la sección sobre la abstracción promesa parece un poco demasiado complicado para mí. se da la siguiente como un ejemplo:

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

Me parece que el siguiente podría proporcionar el mismo resultado con menos líneas de código:

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);
    });
¿Fue útil?

Solución

Si bien es cierto que tanto en última instancia, lograr lo mismo, la diferencia es que el segundo ejemplo no es asíncrona. Por ejemplo, considere lo que sucede si JSON.parse(...) resulta ser una operación extremadamente costosa; que tendrá que pasar hasta que todo está acabado, que no siempre puede ser lo que quiera.

Eso es lo que las promesas que se obtiene: la extraordinaria capacidad de diferir el cálculo de la respuesta correcta hasta un momento más conveniente. Como su nombre indica, el constructo de "promesas" para darle el resultado en algún momento, pero no necesariamente en este momento. Puede leer más acerca de los futuros y las promesas de trabajo en una escala más grande aquí .

Otros consejos

comparar el ejemplo promesa Vamos a un ejemplo de JavaScript puro:

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

Como Norbert señaló Hartl, JSON.parse () va a colgar el navegador para grandes cadenas. Así que utilicé setTimeout () para retrasar su ejecución (después de una pausa de 10 milisegundos). Este es un ejemplo de solución de Kris Kowal. Se permite que la corriente de rosca que Javascript completa, liberando el navegador para presentar cambios DOM y desplazarse por la página para que el usuario, antes de que las carreras de devolución de llamada.

Espero que los CommonJS prometen marco también utiliza algo así como setTimeout, de lo contrario las promesas posteriores en el ejemplo del artículo de hecho se ejecute de forma sincrónica como se temía.

Mi alternativa más arriba se ve bastante feo, con los procesos posteriores que requieren mayor sangría. Reestructuré el código, por lo que podemos ofrecer nuestra cadena de procesos todo en una planta:

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

Me esperaba para demostrar que tradicional visión de pasar de devoluciones de llamada en Javascript es más o menos equivalente a las promesas. Sin embargo, después de dos intentos Parece que he mostrado, con referencia a la pulcritud del código en el ejemplo original, que las promesas son una solución mucho más elegante!

El segundo fragmento es vulnerable al ataque de denegación de servicio porque example.com/foo simplemente puede volver JSON válido para bloquear el servidor. Incluso respuesta vacía es JSON no válido (aunque JS válida). Es como ejemplos mysql_* con deslumbrante orificios de inyección SQL.

Y el código promesa se puede mejorar mucho también. Estos son iguales:

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

Y:

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

Si quisiéramos manejar el error, entonces éstos sería igual:

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

y

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

También se podría añadir que la ventaja de la primera versión sobre la segunda es que separa diferentes operaciones en la cadena de refinamiento (las funciones no tienen que ser escritos en el lugar tampoco). La segunda versión mezclas tanto el análisis de bajo nivel con la lógica de aplicación. Específicamente, utilizando los principios sólidos como directrices, la segunda versión viola tanto OCP y SRP .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top