working with promises nodejs multiple javascript abstraction commonjs promise

javascript - with - using promises js



¿Cuál es el beneficio de una abstracción de ''promesa'' en CommonJS? (4)

Si bien es cierto que ambos finalmente lograrán lo mismo, la diferencia es que su segundo ejemplo no es asincrónico. Por ejemplo, considere lo que sucede si JSON.parse(...) resulta ser una operación extremadamente costosa; Tendrás que esperar hasta que todo haya terminado, lo que puede no ser siempre lo que deseas.

Eso es lo que te ofrecen las promesas: la poderosa capacidad de diferir el cálculo de la respuesta correcta hasta un momento más conveniente. Como su nombre indica, la construcción "promete" darle el resultado en algún momento, pero no necesariamente ahora. Puede leer más sobre los futuros y las promesas de trabajo a mayor escala aquí .

Estoy leyendo este artículo y la sección sobre la abstracción de la promesa me parece un poco demasiado complicada. Lo siguiente se da 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 lo 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); });


Comparemos el ejemplo de promesa con 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 señaló Norbert Hartl, JSON.parse () colgará el navegador para cadenas grandes. Así que utilicé setTimeout () para retrasar su ejecución (después de una pausa de 10 milisegundos). Este es un ejemplo de la solución de Kris Kowal. Permite completar el hilo de Javascript actual, liberando el navegador para presentar los cambios DOM y desplazarse por la página para el usuario, antes de ejecutar la devolución de llamada.

Espero que el marco de promesa de commonjs también use algo como setTimeout, de lo contrario, las últimas promesas en el ejemplo del artículo se ejecutarán sincrónicamente como se temía.

Mi alternativa anterior parece bastante fea, y los procesos posteriores requieren más sangría. Reestructuré el código para poder proporcionar nuestra cadena de procesos en un solo nivel:

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

Tenía la esperanza de demostrar que el tradicional forward-passing de devoluciones de llamada en Javascript es prácticamente equivalente a las promesas. Sin embargo, después de dos intentos, parezco haber demostrado, con referencia a la pulcritud del código en el ejemplo original, ¡que las promesas son una solución mucho más elegante!


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


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

Y el código de promesa también se puede mejorar mucho. 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, estos serían 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); }).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); });