16

Estoy tratando de encontrar la mejor manera de crear llamadas asincrónicas cuando cada llamada depende de la llamada anterior para haber completado. En este momento estoy encadenando los métodos recursivamente llamando a una función de proceso definida como se ilustra a continuación.¿Cuál es la forma correcta de encadenar llamadas asíncronas en javascript?

Esto es lo que estoy haciendo actualmente.

var syncProduct = (function() { 
    var done, log; 
    var IN_CAT = 1, IN_TITLES = 2, IN_BINS = 3; 
    var state = IN_CAT; 
    var processNext = function(data) { 
     switch(state) { 
      case IN_CAT: 
       SVC.sendJsonRequest(url("/api/lineplan/categories"), processNext); 
       state = IN_TITLES; 
       break; 
      case IN_TITLES: 
       log((data ? data.length : "No") + " categories retrieved!"); 
       SVC.sendJsonRequest(url("/api/lineplan/titles"), processNext); 
       state = IN_BINS; 
       break; 
      case IN_BINS: 
       log((data ? data.length : "No") + " titles retrieved!"); 
       SVC.sendJsonRequest(url("/api/lineplan/bins"), processNext); 
       state = IN_MAJOR; 
       break; 
      default: 
       log((data ? data.length : "No") + " bins retrieved!"); 
       done(); 
       break; 
     } 
    } 
    return { 
     start: function(doneCB, logCB) { 
      done = doneCB; log = logCB; state = IN_CAT; 
      processNext(); 
     } 
    } 
})(); 

me permitiría llamar a esto de la siguiente manera

var log = function(message) { 
    // Impl removed. 
} 

syncProduct.start(function() { 
    log("Product Sync Complete!"); 
}, log); 

Aunque esto funciona perfectamente bien para mí No puedo evitar pensar que tiene que haber una manera mejor (más simple). ¿Qué sucede más tarde cuando mis llamadas recursivas se vuelven demasiado profundas?

NOTA: No estoy usando javascript en el navegador pero de forma nativa en el marco de Titanium, esto es similar a Javascript para Node.js.

+1

¿Has visto "promesas"? Pueden encajar bien. [Esta es una biblioteca que lo implementa para Nodo] (https://github.com/kriskowal/q). – pimvdb

+0

Esa biblioteca se ve brillante pimvdb, creo que voy a usar esta. –

Respuesta

26

Hay un montón de librerías y herramientas que hacen el encadenamiento asíncrono y control de flujo para usted y que en su mayoría son de dos tipos principales:

  1. bibliotecas de flujo de control

    Por ejemplo, vea async, seq y step (basado en devolución de llamada) o Q y futures (basado en la promesa). La principal ventaja de estos es que son solo bibliotecas JS de planicies que alivian el dolor de la programación asíncrona.

    En mi experiencia personal, las bibliotecas basadas en promesas tienden a generar un código que se parece más al código síncrono habitual, ya que devuelve valores usando "retorno" y los valores promesas pueden pasarse y almacenarse de manera similar a valores reales.

    Por otro lado, el código basado en la continuación es más bajo ya que manipula explícitamente las rutas de código. Esto posiblemente posibilite un flujo de control más flexible y una mejor integración con las bibliotecas existentes, pero también podría llevar a un código más lento y menos intuitivo.

  2. compiladores
  3. Javascript CPS

    La extensión de la lengua para añadir soporte nativo para corrutinas/generadores le permite escribir código asíncrono de una manera muy sencilla y juega bien con el resto de la lengua significa que puede utilizar JavaScript si declaraciones, bucles, etc. en lugar de necesitar replicarlos con funciones. Esto también significa que es muy fácil convertir el código previamente sincronizado en una versión asíncrona. Sin embargo, existe la desventaja obvia de que no todos los exploradores ejecutarán su extensión de Javascript, por lo que deberá agregar un paso de compilación en su proceso de compilación para convertir su código a JS normal con devoluciones de llamada en el estilo de continuación de paso. De todos modos, una alternativa prometedora son los generadores en la especificación Ecmascript 6, mientras que Firefox solo los admite de forma nativa a partir de ahora, existen proyectos como regenerator y Traceur para compilarlos de nuevo a las devoluciones de llamada. También hay otros proyectos que crean su propia sintaxis asíncrona (ya que los generadores de es6 no habían aparecido en aquel entonces). En esta categoría, encontrará cosas como tamejs y Iced Coffeescript. Finalmente, si usas Node.js allí también puedes echar un vistazo al Fibers.


Mi recomendación:

Si lo que desea es algo simple que no complicarse la acumulación proccess, recomiendo ir con cualquier biblioteca de flujo de control se adapta mejor a su estilo personal y las bibliotecas que ya usas

Sin embargo, si espera escribir muchos códigos asíncronos complicados y profundamente integrados, le recomiendo que al menos busque una alternativa basada en el compilador.

+0

Excelente missingno, la biblioteca 'Q' que pimvdb también mencionó en el comentario de mi pregunta parece perfecta. ¿Podría darnos algún comentario sobre las bibliotecas antes de decidir seguir un camino? Sin embargo, lo que supongo que no quiero es una llamada de bloqueo completo en la primera invocación. –

+2

@BrettRyan: En realidad, trabajo principalmente con material de Dojo toolkit así que tengo la mayor parte de mi experiencia con su biblioteca de promesas y no tengo mucha experiencia con las alternativas. Todos los diferentes estilos deberían poder hacer todas las cosas que no requieren bloqueo, por lo que debes buscar más el estilo de programación de todos modos. Si tuviera que empezar algo ahora, consideraría utilizar un compilador de CPS: realmente no sé cómo resultaría realmente, pero en este momento estoy algo cansado de tener que escribir código CPS manualmente y esperar algo. mejor. – hugomg

+0

Gracias missingno, estoy usando el SDK móvil de Appcelerator Titanium por lo que realmente no quiero poner otra herramienta en la cadena de herramientas. Experimentar con la biblioteca Q realmente parece un ajuste natural. –

Cuestiones relacionadas