Animación impulsada por la promesa -- javascript campo con asynchronous campo con promise campo con animation camp codereview Relacionados El problema

Promise-driven animation


2
vote

problema

Español

inspirado en esta pregunta sobre el desbordamiento de la pila , he intentado codificar tal Animación, sobre todo para obtener más práctica con Async, Promesas y Q.js:

(Demo en vivo)

  function addOutput(s) {   $('<div>').text(s).appendTo(wnd);   //return Q.defer().promise;   return Q.delay(100).then(function() { return addPrompt(); }); }  function addInput(s) {   var l = $('.prompt:last');   return addLettersRecursive(l, s); }  function addPrompt() {   var prompt = "kos@codepen % ";   var l = $('<div>').text(prompt).addClass('prompt').appendTo(wnd);   return Q.delay(900); }  function addLettersRecursive(container, s) {   container.append(s.charAt(0)); // dangerous :(   var row_complete = Q.defer();   Q.delay(100).then(function() {     if (s.length <= 1) {       Q.delay(300).then(function() {         row_complete.resolve();       });     }     addLettersRecursive(container, s.substr(1)).then(function() {       row_complete.resolve();     })   });   return row_complete.promise; }  // Usage  addPrompt(">>> ") .then(function() { return addInput("whoami"); }) .then(function() { return addOutput("kos"); }) .then(function() { return addInput("uname -a"); }) .then(function() { return addOutput("Javascript in codepen.io, powered by Q.js"); }) .then(function() { return addInput("raz dwa"); }) .then(function() { return addOutput("zsh: command not found: raz"); }) .then(function() { return addInput("trzy cztery"); }) .then(function() { return addOutput("zsh: command not found: trzy"); }) .done();   

No estoy realmente satisfecho con esta implementación, sin embargo. ¿Cómo puedo simplificarlo? Aquí están las preocupaciones específicas que tengo:

  1. I implementé addInput En términos de una función de ayuda recursiva addLettersRecursive que aún es demasiado complicado de acuerdo con mi sensación intestinal.
  2. Hay este .then(function() { return function_that_returns_promise(args); }); Pattern, lo que parece una forma muy verbosa de encadenar el comportamiento.

lo que he intentado:

  1. Intenté relajar la recursión al apilar las promesas uno encima de otro en un bucle, que fue un poco complicado para implementar debido al cierre selectivo involucrado. Hay algo de mejora, pero aún se ve desordenado:

      function addInput(s) {   var container = $('.prompt:last');   var d = Q.delay(0);   for (var i=0; i<s.length; ++i) {     d = d.then(function(i) { return function() { // pass i by value       container.append(s.charAt(i));       return Q.delay(100);     }}(i));   }   return d.then(function() { return Q.delay(300); }); }   
  2. No estoy seguro de que este tipo de patrón es típico del código impulsado por la promesa, o simplemente estoy haciendo algo subopimemente. Una cosa que vino a mi mente es esta sustitución:

        /* before */ .then(function() { return addInput("whoami"); })   /* after  */ .then(addInput.bind(null, "whoami"))    /* before */ return d.then(function() { return Q.delay(300); });   /* after  */ return d.then(Q.delay.bind(Q, 300));   

    ¿Es una buena pista?

En general, no he visto muchos usos de "vida real" de las promesas, excepto los casos del libro, por lo que si algo más se ve fuera de lo común o subóptimo, levántelo.

Original en ingles

Inspired by this question on Stack Overflow, I've attempted to code such animation, mostly to get some more practice with async, promises and Q.js:

(Live demo)

function addOutput(s) {   $('<div>').text(s).appendTo(wnd);   //return Q.defer().promise;   return Q.delay(100).then(function() { return addPrompt(); }); }  function addInput(s) {   var l = $('.prompt:last');   return addLettersRecursive(l, s); }  function addPrompt() {   var prompt = "kos@codepen % ";   var l = $('<div>').text(prompt).addClass('prompt').appendTo(wnd);   return Q.delay(900); }  function addLettersRecursive(container, s) {   container.append(s.charAt(0)); // dangerous :(   var row_complete = Q.defer();   Q.delay(100).then(function() {     if (s.length <= 1) {       Q.delay(300).then(function() {         row_complete.resolve();       });     }     addLettersRecursive(container, s.substr(1)).then(function() {       row_complete.resolve();     })   });   return row_complete.promise; }  // Usage  addPrompt(">>> ") .then(function() { return addInput("whoami"); }) .then(function() { return addOutput("kos"); }) .then(function() { return addInput("uname -a"); }) .then(function() { return addOutput("Javascript in codepen.io, powered by Q.js"); }) .then(function() { return addInput("raz dwa"); }) .then(function() { return addOutput("zsh: command not found: raz"); }) .then(function() { return addInput("trzy cztery"); }) .then(function() { return addOutput("zsh: command not found: trzy"); }) .done(); 

I'm not really satisfied by this implementation, though. How can I simplify it? Here are the specific concerns I have:

  1. I implemented addInput in terms of a recursive helper function addLettersRecursive which still is overly complicated according to my gut feeling.
  2. There's this .then(function() { return function_that_returns_promise(args); }); pattern all over, which seems like a very verbose way of chaining behaviour.

What I have tried:

  1. I attempted to unwind the recursion by stacking the promises one on top of another in a loop, which was a bit tricky to implement because of the selective closure involved. There's some improvement but still looks messy:

    function addInput(s) {   var container = $('.prompt:last');   var d = Q.delay(0);   for (var i=0; i<s.length; ++i) {     d = d.then(function(i) { return function() { // pass i by value       container.append(s.charAt(i));       return Q.delay(100);     }}(i));   }   return d.then(function() { return Q.delay(300); }); } 
  2. I'm not sure if this kind of pattern is typical to promise-driven code, or I'm just doing something sub-optimally. One thing that came to my mind is this substitution:

      /* before */ .then(function() { return addInput("whoami"); })   /* after  */ .then(addInput.bind(null, "whoami"))    /* before */ return d.then(function() { return Q.delay(300); });   /* after  */ return d.then(Q.delay.bind(Q, 300)); 

    Is it a good track?

Generally I haven't seen much "real life" uses of promises yet except the book cases, so if anything else looks out of the ordinary or sub-optimal, please raise it.

           

Lista de respuestas

2
 
vote

Esta esencia es difícil de conseguir, en este punto, el código de buena promesa, el código impulsado parece más a un arte que la ingeniería.

Desde una perspectiva de CODEREVIEW, su código es bastante fácil de seguir, excepto por una cosa que me dieron una perpleja por un rato, 99887776655544330 debe ser llamado char_complete , y luego, de repente, addLettersRecursive tendrá más sentido.

Hay al menos 3 formas adicionales que puede tratar con .then(function() { return function_that_returns_promise(args); });

  1. Cambie sus funciones (como addInput ) para devolver una función, como esta:

      function addInput(s) {   return function addInputWrapper(){     var l = $('.prompt:last');     return addLettersRecursive(l, s);   } }   

    Luego, puede llamar simplemente .then( addInput( 'whoami' ) )

  2. Crear una función de envoltura genérica como esta:

      function wrap( f ){   var args = Array.prototype.slice.call(arguments,1);   return function wrapper(){     return f.apply( this, args );   } }   

    Luego, puede llamar .then( wrap( addInput, 'whoami' ) )

  3. GENERAR UN lambdafy FUNCIÓN COMO ESTE:

      char_complete0  

    Luego, puede char_complete1 y char_complete2

 

This stuff is hard to get right, at this point good promise driven code seems more like an art than engineering.

From a CodeReview perspective, your code is fairly easy to follow, except for one thing which got me stumped for a little while, row_complete should really be named char_complete, and then suddenly addLettersRecursive will make more sense.

There are at least 3 additional ways you can deal with .then(function() { return function_that_returns_promise(args); });

  1. Change your functions ( like addInput ) to return a function, like this:

    function addInput(s) {   return function addInputWrapper(){     var l = $('.prompt:last');     return addLettersRecursive(l, s);   } } 

    Then you can call simply .then( addInput( 'whoami' ) )

  2. Create a generic wrapper function like this:

    function wrap( f ){   var args = Array.prototype.slice.call(arguments,1);   return function wrapper(){     return f.apply( this, args );   } } 

    Then you can call .then( wrap( addInput, 'whoami' ) )

  3. Generate a lambdafy function like this :

    function lambdafy( f ) {   var lambda = function(){     var args = Array.prototype.slice.call(arguments);     return function(){       f.apply( this , args );     }   }   return lambda; } 

    Then you can addInput = lambdafy( addInput ) and .then( addInput( 'whoami' ) )

 
 
 
 

Relacionados problema

7  Una secuencia parcialmente superpuesta de animaciones jQuery  ( A partially overlapping sequence of jquery animations ) 
¡Sé que este es un desastre! ¿Cómo puedo escribir este código mejor? function anim() { $( "#p1-animation-1" ).fadeIn( 1200, function() { ...

2  Animaciones de la línea de tiempo  ( Timeline animations ) 
Hice recientemente esta línea de tiempo del campus para mi universidad. Al ver la línea de tiempo en un dispositivo móvil (no una tableta), la barra de nave...

2  Animar una caja, rebotando a la izquierda y la derecha  ( Animate a box bouncing left and right ) 
Escribí el siguiente código para mover un cuadro a la derecha y devolverlo a la izquierda, y repetir esta acción para siempre. Este código funciona, pero ¿h...

2  Los efectos de desplazamiento, fade-in y fade-out se sienten clunky  ( Scrolling fade in and fade out effects feeling clunky ) 
Estoy cerca de terminar un sitio donde hay una serie de funciones de jQuery que están pasando. Todos trabajan, pero la página está corriendo un poco demasiado...

1  Animación "Star Field" con JavaScript y Sass-CSS  ( Star field animation with javascript and sass css ) 
He hecho esta animación el fin de semana como una cosa "solo por diversión". Y para jugar con varias técnicas que he visto en otros Código. Creo que funcion...

1  Manipulador de eventos repetitivos para un control de interfaz de usuario de la UI  ( Repetitive event handler for a toggling ui control ) 
Siento que este tipo de código podría haber sido escrito más elegante, especialmente con las enormes afirmaciones de IF / ODS. ¿Alguien puede ayudarme a rompe...

3  Forma aceptable de usar métodos jQuery en directivas angulares  ( Acceptable way of using jquery methods in angular directives ) 
aquí es mi ejemplo de plunker de lo que estoy haciendo. jQuery es una excelente manera de usar transiciones de diapositivas y parece funcionar bien con an...

12  Impresión similar a la consola del mensaje JavaScript  ( Console like printing of message javascript ) 
Estoy aprendiendo a Javascript y he hecho un pequeño script de modificación de documentos muy simple que imprime un mensaje como si fuera alguien escribiendo ...

3  Cajas de texto ampliables para leyendas de campos  ( Expandable text boxes for legends of fieldsets ) 
¿Cuál es la mejor manera de refactorizar el siguiente script? <?php // First we execute our common code to connection to the database and start the s...

4  Carrusel para sitio web  ( Carousel for website ) 
He estado construyendo mi propio carrusel en los últimos días. No soy un guru jquery, solo un entusiasta, y creo que mi código es un poco descuidado, de ahí l...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos