2012-04-06 7 views
6

Recuerda "envenenamiento por const" en C++, cuando marcarías un método como const y luego te darás cuenta de que tienes que marcar todos los métodos que llamó como const y luego todo el métodos que llamaron, y así sucesivamente?Envenenamiento asincrónico: no puedo ser el único que sufre

Tengo un problema con la intoxicación asincrónica, en Javascript, aunque no creo que sea relevante, aunque se propaga en lugar de disminuir. Cuando una función puede llamar a una función asíncrona, debe volverse a escribir como asíncrona, y luego deben ser todas las funciones que la invocan, y así sucesivamente.

No tengo una pregunta bien formada aquí (lo siento, mods) pero esperaba que alguien tuviera (un) consejo o (b) una referencia que podría tener (a).

+1

Algunos ejemplos (con código) serían agradables (para mí). –

+0

¿No es esta la razón por la cual las devoluciones de llamada son para? Si esto es lo que estás preguntando, no lo entendí del todo. – Bakudan

Respuesta

1

La mejor solución que he visto hasta ahora es promises. Todo lo que ocurre, por supuesto, es que intercambias asincronía por envenenamiento prometedor (ya que cualquier cálculo que depende de una promesa en sí debe devolver una promesa , pero las promesas son mucho más flexibles y potentes que las devoluciones de llamadas.

0

Si el problema es b() debe bloquearse hasta que finalice pero llama a asincrónico a(), entonces quizás una devolución de llamada desde a() podría establecer una bandera y b() relojes para la bandera. Si a() no ofrece una devolución de llamada, entonces tal vez exista un valor en algún lugar que cambie una vez que a() se complete.

2

No es una mala pregunta. Sin embargo, hay algunas formas de evitar totalmente el flujo de control. Nota: No dije que era bonita.

Suponga que tiene objetos A, B, C y D, A.Amethod no devuelve nada y llama a un método getBData de B, B llama getCData método C, y la cuestión se llamaba C D algo así como lo que

var data = D.getRawData(); 
... something to be done with data ... 
... something else to be done with data... 

y ahora tiene que ser escrita como

D.getData(function(data){ 
    ... something to be done with data ... 
    ... something else to be done with data... 
}); 

así, siempre se puede añadir un parámetro de devolución de llamada a cada uno de sus métodos, de modo que para el código el código que utiliza para parecerse a:

var A = { 
//I'm not recommending coding like this, just for demonstration purposes. 
... 
    Amethod: function(x,y,z){ 
     var somethingForA = this.B.getBData(1,2,3); 
     astatement1; 
     astatement2; 
     ... 
    } 
    ... 
    }  
    //end of A 
    ... 
var B = { 
... 
    Bmethod: function(x,y,z){ 
     var somethingForB = this.C.getCData(1,2,3); 
     bstatement1; 
     var somethingFromB = bstatement2; 
     return somethingFromB; 
    } 
    ... 
    }  
    //end of B 
    ... 
var C = { 
... 
    Cmethod: function(x,y,z){ 
     var somethingForC = this.D.getRawData(1,2,3) 
     cstatement1; 
     var somethingFromC = cstatement2; 
     return somethingFromC; 
    } 
    ... 
    }  
    //end of C 
    ... 

te había ahora tienen:

var A = { 
    ... 
    Amethod: function(x,y,z){ 
     this.B.getBData((1,2,3,function(somethingForA){ 
      astatement1; 
      astatement2; 
     }); 
     ... 
    } 
    ... 
    }  
    //end of A 
    ... 
var B = { 
... 
    Bmethod: function(x,y,z,callback){ 
     this.C.getCData(1,2,3,function(somethingForB){ 
      bstatement1; 
      var somethingFromB = bstatement2; 
      callback(somethingFromB); 
     }); 
     ... 
    } 
    ... 
    }  
    //end of B 
    ... 
var C = { 
... 
    Cmethod: function(x,y,z,callback){ 
     this.D.getRawData(1,2,3,function(somethingForC) { 
      cstatement1; 
      var somethingFromC = cstatement2; 
      callback(somethingFromC); 
     }); 
    } 
    ... 
    }  
    //end of C 
    ... 

Eso es más o menos una refactorización sencilla utilizando funciones anónimas para implementar toda la funcionalidad de mantener su flujo de control. No sé cuán literal sería una transformación; es posible que tenga que hacer algún ajuste para el alcance variable. Y, obviamente, no es tan bonito.

¿Hay otras formas? Por supuesto. Como puede ver, lo anterior es complicado, y esperamos evitar escribir código desordenado. Qué menos desordenado depende del contexto.

No es necesario pasar un parámetro de devolución de llamada, cualquier devolución de llamada necesaria se podría pasar a los objetos de antemano, o se puede pasar como uno de los elementos en un parámetro. Puede que no sea necesario invocar directamente la devolución de llamada, sino invocarla de forma indirecta utilizando uno de los diversos métodos de gestión de eventos disponibles (para lo cual deberá consultar las bibliotecas que desee utilizar) y los datos se pueden pasar cuando el evento se desencadena O tal vez hay un "DataGetter" global que A puede registrar una devolución de llamada siempre que los datos se "obtienen" para evitar por completo a los intermediarios B y C.

Por último, existe la consideración de que si estás hasta las rodillas en invocaciones solo para descubrirlo necesita algo que solo se puede obtener de forma asincrónica, y que los datos deben pasarse por la cadena de comando, puede que esté haciendo algo un poco al revés en términos de qué objetos deberían controlar el flujo de la lógica del programa (sinceramente estoy perplejo a cómo describir por qué creo que este escenario es problemático, sin embargo.) Tiendo a pensar, como las instancias de A tienen que contener instancias de B, B contienen instancias de C, etc., las instancias que crean las subinstancias como parte de su composición deben tener cierto grado de control sobre cómo las sub-instancias pueblan ellos mismos, en lugar de dejar que las sub-instancias decidan por completo ... si eso tiene sentido :-(

En este momento siento que estoy divagando un poco, así que espero que alguien explique los problemas mejor que yo!

Cuestiones relacionadas