sincronas promesas pagina funciones funcion ejemplo ejecutar ejecucion controlar codigo cargar await async asincrono asincronia asincrona antes anidadas javascript node.js asynchronous callback

javascript - pagina - js promesas anidadas



Devolución de llamada después de todo asíncrono para cada devolución de llamada se completan (11)

¡Es extraño cuántas respuestas incorrectas se han dado al caso asincrónico ! Se puede demostrar simplemente que el índice de verificación no proporciona el comportamiento esperado:

// INCORRECT var list = [4000, 2000]; list.forEach(function(l, index) { console.log(l + '' started ...''); setTimeout(function() { console.log(index + '': '' + l); }, l); });

salida:

4000 started 2000 started 1: 2000 0: 4000

Si buscamos el index === array.length - 1 , se llamará a la devolución de llamada una vez completada la primera iteración, ¡mientras que el primer elemento aún está pendiente!

Para resolver este problema sin utilizar bibliotecas externas como async, creo que la mejor opción es guardar la longitud de la lista y disminuirla después de cada iteración. Como solo hay un hilo, estamos seguros de que no hay posibilidad de una condición de carrera.

var list = [4000, 2000]; var counter = list.length; list.forEach(function(l, index) { console.log(l + '' started ...''); setTimeout(function() { console.log(index + '': '' + l); counter -= 1; if ( counter === 0) // call your callback here }, l); });

Como sugiere el título. ¿Cómo hago esto?

Quiero llamar a whenAllDone() después de que forEach-loop haya revisado cada elemento y haya realizado un procesamiento asincrónico.

[1, 2, 3].forEach( function(item, index, array, done) { asyncFunction(item, function itemDone() { console.log(item + " done"); done(); }); }, function allDone() { console.log("All done"); whenAllDone(); } );

¿Es posible hacer que funcione así? ¿Cuando el segundo argumento para forEach es una función de devolución de llamada que se ejecuta una vez que pasó por todas las iteraciones?

Rendimiento esperado:

3 done 1 done 2 done All done!


¿Qué tal setInterval, para verificar el conteo de iteración completa, trae garantía. Sin embargo, no estoy seguro si no sobrecargará el alcance pero lo uso y parece ser el

_.forEach(actual_JSON, function (key, value) { // run any action and push with each iteration array.push(response.id) }); setInterval(function(){ if(array.length > 300) { callback() } }, 100);


Espero que esto solucione tu problema, generalmente trabajo con esto cuando necesito ejecutar para cada uno con tareas asincrónicas dentro.

foo = [a,b,c,d]; waiting = foo.length; foo.forEach(function(entry){ doAsynchronousFunction(entry,finish) //call finish after each entry } function finish(){ waiting--; if (waiting==0) { //do your Job intended to be done after forEach is completed } }

con

function doAsynchronousFunction(entry,callback){ //asynchronousjob with entry callback(); }



Intento Easy Way para resolverlo, compartirlo contigo:

let counter = 0; arr.forEach(async (item, index) => { await request.query(item, (err, recordset) => { if (err) console.log(err); //do Somthings counter++; if(counter == tableCmd.length){ sql.close(); callback(); } });

request es Función de la biblioteca mssql en el nodo js. Esto puede reemplazar cada función o Código que desee. Buena suerte


Mi solución sin Promesa (esto garantiza que cada acción finalice antes de que comience la próxima):

Array.prototype.forEachAsync = function (callback, end) { var self = this; function task(index) { var x = self[index]; if (index >= self.length) { end() } else { callback(self[index], index, self, function () { task(index + 1); }); } } task(0); }; var i = 0; var myArray = Array.apply(null, Array(10)).map(function(item) { return i++; }); console.log(JSON.stringify(myArray)); myArray.forEachAsync(function(item, index, arr, next){ setTimeout(function(){ $(".toto").append("<div>item index " + item + " done</div>"); console.log("action " + item + " done"); next(); }, 300); }, function(){ $(".toto").append("<div>ALL ACTIONS ARE DONE</div>"); console.log("ALL ACTIONS ARE DONE"); });

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="toto"> </div>


Mi solución:

//Object forEachDone Object.defineProperty(Array.prototype, "forEachDone", { enumerable: false, value: function(task, cb){ var counter = 0; this.forEach(function(item, index, array){ task(item, index, array); if(array.length === ++counter){ if(cb) cb(); } }); } }); //Array forEachDone Object.defineProperty(Object.prototype, "forEachDone", { enumerable: false, value: function(task, cb){ var obj = this; var counter = 0; Object.keys(obj).forEach(function(key, index, array){ task(obj[key], key, obj); if(array.length === ++counter){ if(cb) cb(); } }); } });

Ejemplo:

var arr = [''a'', ''b'', ''c'']; arr.forEachDone(function(item){ console.log(item); }, function(){ console.log(''done''); }); // out: a b c done


No debería necesitar una devolución de llamada para iterar a través de una lista. Simplemente agregue la llamada al end() después del ciclo.

posts.forEach(function(v, i){ res.write(v + ". Index " + i); }); res.end();


Una solución simple sería como seguir

function callback(){console.log("i am done");} ["a", "b", "c"].forEach(function(item, index, array){ //code here if(i == array.length -1) callback() }


si encuentra funciones asíncronas, y quiere asegurarse de que antes de ejecutar el código finalice su tarea, siempre podemos usar la función de devolución de llamada.

por ejemplo:

var ctr = 0; posts.forEach(function(element, index, array){ asynchronous(function(data){ ctr++; if (ctr === array.length) { functionAfterForEach(); } }) });

nota: functionAfterForEach es la función que se ejecutará después de que las tareas de foreach hayan finalizado. asincrónico es la función asíncrona ejecutada dentro de foreach.

espero que esto ayude.


Array.forEach no proporciona esta calidad (oh, si lo fuera), pero hay varias formas de lograr lo que desea:

Usando un simple contador

function callback () { console.log(''all done''); } var itemsProcessed = 0; [1, 2, 3].forEach((item, index, array) => { asyncFunction(item, () => { itemsProcessed++; if(itemsProcessed === array.length) { callback(); } }); });

(gracias a @vanuan y otros) Este enfoque garantiza que todos los elementos se procesen antes de invocar la devolución de llamada "realizada". El enfoque que sugiere Emil, aunque generalmente es efectivo en mi experiencia, no ofrece la misma garantía.

Usando ES6 Promises

(una biblioteca de promesas se puede usar para navegadores antiguos):

  1. Procese todas las solicitudes que garanticen la ejecución sincrónica (p. Ej., 1, luego 2 y 3)

    function asyncFunction (item, cb) { setTimeout(() => { console.log(''done with'', item); cb(); }, 100); } let requests = [1, 2, 3].reduce((promiseChain, item) => { return promiseChain.then(() => new Promise((resolve) => { asyncFunction(item, resolve); })); }, Promise.resolve()); requests.then(() => console.log(''done''))

  2. Procese todas las solicitudes asincrónicas sin ejecución "síncrona" (2 pueden finalizar más rápido que 1)

    let requests = [1,2,3].map((item) => { return new Promise((resolve) => { asyncFunction(item, resolve); }); }) Promise.all(requests).then(() => console.log(''done''));

Usando una biblioteca asíncrona

Existen otras bibliotecas asíncronas, siendo async la más popular, que proporcionan mecanismos para expresar lo que desea.

Editar

El cuerpo de la pregunta ha sido editado para eliminar el código de ejemplo previamente sincrónico, así que actualicé mi respuesta para aclarar. El ejemplo original utilizaba código sincrónico similar para modelar el comportamiento asincrónico, por lo que se aplica lo siguiente:

array.forEach es synchronous y también lo es res.write , por lo que simplemente puede poner su devolución de llamada después de su llamada a foreach:

posts.foreach(function(v, i) { res.write(v + ". index " + i); }); res.end();