Zef Hemel publicó hace unos días un script capaz de convertir el ya conocido forEach()
de Javascript en una versión asíncrona de la misma.
forEach()
Como ya sabemos desde la revisión 1.6 de Javascript (Firefox, Netscape 7/8, Opera 7+) el objeto Array
dispone de un método que permite recorrer sus elementos de una forma sencilla y recursiva, permitiéndonos definir una funcionalidad que será ejecutada para cada una de las posiciones del Array
.
var _array = ["casa", "coche", "pelota"];
_array.forEach(function(item){
console.log("_array contiene ->" + item);
});
Por el momento, no todos los navegadores disponen de ellos, y la mayoría de frameworks JS se encargan de definir su propia versión para facilitar el desarrollo. Mozilla Developer Center ofrece una versión interesante:
if (!Array.prototype.forEach)
{
Array.prototype.forEach = function(fun /*, thisp */)
{
"use strict";
if (this === void 0 || this === null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== "function")
throw new TypeError();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in t)
fun.call(thisp, t[i], i, t);
}
};
}
El problema es que este sistema es completamente síncrono, osea realiza una funcionalidad y luego otra, mientras haya elementos en el Array
. Para esto, Zef, presenta la siguiente propuesta:
function asyncForEach(array, fn, callback) {
array = array.slice(0);
function processOne() {
var item = array.pop();
fn(item, function(result) {
if(array.length > 0) {
setTimeout(processOne, 0); // schedule immediately
} else {
callback(); // Done!
}
});
}
if(array.length > 0) {
setTimeout(processOne, 0); // schedule immediately
} else {
callback(); // Done!
}
};
Básicamente se trata de una fnción que se llama a si misma recursivamente por cada elemento del Array
. Para evitar que el navegador nos alerte de una ejecución muy larga, con Arrays
de 1000 elementos o más, se usa el viejo truco del setTimeout()
que permite ejecutar funcionalidades por un tiempo indefinido.
A raiz de este artículo han ido apareciendo implementaciones varias usando la misma técnica:
Al igual que Zef, opino que esta funcionalidad es muy pesada y consume una gran cantidad de recursos, pero nos permite trabajar con una cántidad de datos de forma asíncrona. Por lo tanto, a usarla con cabeza 😀
Actualización:
Chuso me avisa de un artículo que ha escrito hace unos días sobre el tema, quizás te pueda interesar.