Skip to content
Chelo Quilón edited this page Jun 18, 2015 · 1 revision

Procedure Class

Simple JS async development, What promise?

La librería soluciona la problemática de tener diversas llamadas a funciones asíncronas, y éstas se necesitan resolver de forma secuencial o por conjuntos, y que cuando finalice la última función en ejecutarse, podamos tener control sobre los resultados. Cada función, para devolver la información de su finalización y datos adicionales, debe realizar como última instrucción this.done().

Con Procedure se declara un Procedimiento, entendiendo un procedimiento como un conjunto de trámites que hay que realizar de forma secuencial y ordenada para completarlo. Una vez estén todos añadidos mediante .add(), ejecutamos el procedimiento con .launch() y se ejecutarán todas las funciones de forma secuencial, es decir, sin asincronismos.

require('procedure');

##Forma básica de crear un procedimiento

Este procedimiento ejecuta secuencialmente a cada función func, llamando a cada función con los parámetros declarados en args. Importante, cada función debe tener como última línea this.done();

var procedure = new Procedure({});

procedure
.add(func1, args1)
.add(func2, args2)
.add(func3, args3)
....
.add(funcN, argsN)
.launch();

Se instancia la clase en procedure y mediante .add(*función*, *argumentos*) se le añade la función a ejecutar junto con los parámetros con los que será llamada. .launch() lanza el procedimiento, y se comienzan a ejecutar las funciones sin asincronía, es decir, cuando finalice func1, se ejecutará func2, y así hasta que finalice la cola de funciones añadidas al procedimiento.

Si ocurre algún error en la ejecución de alguna de las funciones, se manda el error a .launch().

Construcción

var procedure = new Procedure(*object*); 
  • object: objeto de compartirán todos los jobs. this.data; Estos parámetros estarán disponibles para todas las funciones añadidas al procedimiento.

Métodos

  • .add(func [, args]): añade al procedimiento una función y si es necesario los argumentos con los que la función será llamada.
  • .queue([handler]): se empaquetan todas las funciones añadidas a procedure, cuando se ejecute .launch() se ejecutarán todas estas funciones de forma secuencial y ordenada.
  • .race([handler]): se empaquetan todas las funciones añadidas a procedure, cuando se ejecute .launch(), se ejecutarán todas estas funciones de forma concurrente, y por lo tanto sin orden.

Al callback del método .launch() llegarán errores si los hay, y será llamado cuando finalicen todas y cada una de las funciones que se han añadido.

Empaquetar funciones

Las funciones añadidas al procedimiento se pueden empaquetar. Al empaquetar varias funciones especificamos cómo se ejecutarán: si de forma síncrona, mediante .queue(), o asíncrona mediante .race(). Todos los paquetes serán ejecutados de forma secuencial cuando se ejecute el método .launch().

var procedure = new Procedure();

procedure
.add(func1, args1)
.add(func2, args2)
.add(func3, args3)
.queue()

.add(func4, args4)
.add(func5, args5)
.add(func6, args6)
.race()

.launch(function(error){
  if(error){
    console.log("One Error:",error);
  } else {
    console.log("All finished");
  }
});

Añadir trabajos repetitivos

Gracias a la clase Procedure podemos realizar algo impensable en JS, meter un o varias funciones en un bucle y que se ejecuten de forma secuencial.

var procedure = new Procedure();

for(var i=0;i<10;i++){
  procedure.add(func,"args["+i+"]");
}

.launch(function(error){
  if(error){
    console.log("One Error:",error);
  } else {
    console.log("All finished");
  }
});

Ejemplos

###Ejemplo 1 Ejemplo funcional de cómo se añaden 5 funciones pasándole diferentes parámetros. Cada función sumará 1 al contador general counter.

var Myhand = function(name){
  var job = this;
  console.log(name);
  job.data.counter++;
  job.done();
};

var procedure = new Procedure({counter:10}); // <- Initial data for share.

procedure
.add(Myhand,"Queue[A][1]")
.add(Myhand,"Queue[A][2]")
.add(Myhand,"Queue[A][3]")
.add(Myhand,"Queue[A][4]")
.add(Myhand,"Queue[A][5]")


// Queue execution (in order) of pending jobs.
.queue(function(error){
  if(!error){
    console.log("Queue[A] finished!");
    console.log("Counter:",this.data.counter);
  }
})
;

// And finally launch!
procedure
.launch(function(error){
  if(error){ // Called by each error.
    console.log("One Error:",error);
  } else { // Called only if finished whitout errors.
    console.log("All finished");
    console.log("Counter:",this.data.counter);
  }
});

Código del ejemlo en JSfiddle

###Ejemplo 2 En este ejemplo vemos como la Clase Procedure permite hacer uso de bucles para añadir el par func,args mediante el método .add(). En este ejemplo se añaden 10 funciones y se empaquetan para ser ejecutadas en paralelo mediante el método .race(). Posteriormente se le añaden otras 10 funciones más y se empaquetan para ser ejecutadas en serie mediante .queue().

Se añaden otras 3 funciones más, pero no se empaquetan.

Finalmente mediante .launch(), se ejecuta el primer paquete programado, luego el segundo, y por último las tres funciones añadidas.

// Add repetitive jobs - Race version
for(var i=0;i<10;i++){ // <- Add repetitive jobs whith variable arguments.
  procedure.add(Myhand,"Race[B]["+i+"]");
}
procedure.race(function(error){
  if(!error){
    console.log("Race[B] finished!");
    console.log("Counter:",this.data.counter);
  }
});

// Add repetitive jobs - Queue version
for(var i=0;i<10;i++){
  procedure.add(Myhand,"Queue[B]["+i+"]");
}
procedure.queue(function(error){
  if(!error){
    console.log("Queue[B] finished!");
    console.log("Counter:",this.data.counter);
  }
});


// Add independent jobs
procedure.add(Myhand,"independent[X]");
procedure.add(Myhand,"independent[Y]");
procedure.add(Myhand,"independent[Z]");


// And finally launch!
procedure
.launch(function(error){
  if(error){ // Called by each error.
    console.log("One Error:",error);
  } else { // Called only if finished whitout errors.
    console.log("All finished");
    console.log("Counter:",this.data.counter);
  }
});

Código del ejemplo en JSfiddle

###Ejemplo 3 En este ejemplo vemos que ocurre si hay errores en la ejecución de alguna función.

var Myhand = function(name){
  var job = this;
  console.log(name);
  job.data.counter++;
  job.done();
};
// Errors management
var procedure = new Procedure({counter:10}); // <- Initial data for share.
procedure
.add(Myhand,"Queue[C][1]")
.add(Myhand,"Queue[C][2]")
.add(function(){
  var job = this;
  console.log("Queue[C][3] Throw Error!...");
  try {
    var a = b;
    job.done();
  } catch(error) {
    job.error(error);
  }
})
.add(Myhand,"Queue[C][4]")
.add(Myhand,"Queue[C][5]")
.launch(function(error){
  if(error){
    console.log("One Error:",error);
  } else {
    console.log("All finished");
    console.log("Counter:",this.data.counter);
  }
});

Código del ejemplo en JSfiddle

#Licencia MIT