Resumen: ¿Existen algunos patrones de mejores prácticas bien establecidos que pueda seguir para mantener mi código legible a pesar de usar código asincrónico y devoluciones de llamada?
Estoy usando una biblioteca de JavaScript que hace muchas cosas de forma asíncrona y depende en gran medida de las devoluciones de llamada. Parece que escribir un método simple de "carga A, carga B, ..." se vuelve bastante complicado y difícil de seguir usando este patrón.
Permítanme dar un ejemplo (artificial). Digamos que quiero cargar un montón de imágenes (asincrónicamente) desde un servidor web remoto. En C # / async, escribiría algo como esto:
disableStartButton();
foreach (myData in myRepository) {
var result = await LoadImageAsync("http://my/server/GetImage?" + myData.Id);
if (result.Success) {
myData.Image = result.Data;
} else {
write("error loading Image " + myData.Id);
return;
}
}
write("success");
enableStartButton();
El diseño del código sigue el "flujo de eventos": primero, se deshabilita el botón de inicio, luego se cargan las imágenes ( await
asegura que la IU se mantenga receptiva) y luego se vuelve a habilitar el botón de inicio.
En JavaScript, usando devoluciones de llamada, se me ocurrió esto:
disableStartButton();
var count = myRepository.length;
function loadImage(i) {
if (i >= count) {
write("success");
enableStartButton();
return;
}
myData = myRepository[i];
LoadImageAsync("http://my/server/GetImage?" + myData.Id,
function(success, data) {
if (success) {
myData.Image = data;
} else {
write("error loading image " + myData.Id);
return;
}
loadImage(i+1);
}
);
}
loadImage(0);
Creo que los inconvenientes son obvios: tuve que volver a trabajar el bucle en una llamada recursiva, el código que se supone que debe ejecutarse al final está en algún lugar en el medio de la función, el código que comienza la descarga ( loadImage(0)
) está en la parte inferior, y generalmente es mucho más difícil de leer y seguir. Es feo y no me gusta.
Estoy seguro de que no soy el primero en encontrar este problema, así que mi pregunta es: ¿Existen algunos patrones de mejores prácticas bien establecidos que pueda seguir para mantener mi código legible a pesar de usar código asincrónico y devoluciones de llamada?
LoadImageAsync
de hecho es una llamada Ext.Ajax.request
de Sencha Touch.
async.waterfall
es su respuesta.