Reputation: 58
I'm having an issue with a promise inside a loop. I have 10000 rows in databse, and I wanna print first 1000 rows and then, fetch 9 requests to print the rest. Technically, I want to print the 1000 results on each iteration of loop, for that, I'm using a promise for get the data, and .THEN create 1000 rows and print it.
But the problem is that first JavaScript's loops get's the 10 requests and then, execute the 10 .THEN together.
I mean:
1000 results (First loop)
2000 results (Second loop) - Append 1000 new rows to last 1000.
3000 results (Third loop) - Append 1000 new rows to last 2000.
....
What I obtain:
In the last image, "first for loop" are getting 10 requests and, when the loop finishes, .THEN print each promise callback (.THEN)
That's my code:
fetchData('ArticulosSearch', inputValues).then(function (data) {
console.log(data);
var source = getGridSource(url, datafields, "array", data);
// Creamos el grid con las primeras 1000 rows obtenidas
$("#GridAseguradora").createGrid(source, dataColumns, params);
//Obtenemos el nº de registros que tiene la bbdd para calcular cuantas peticiones debe hacer
setTimeout(() => {
fetchData('ArticulosSearchCount', inputValues).then(function (total_rows) {
console.log("count");
console.log(total_rows);
var filt = (total_rows[0].Column1 / 1000) //pagines - peticiones
console.log(filt);
// Creamos promesa para añadir posteriormente las filas al grid una vez hayan terminado todas las peticiones
for (var i = 1; i < filt; i++) {
(function (i) {
console.log("first for loop");
inputValues.offset = (1000 * i)
fetchData('ArticulosSearch', inputValues).then(function (data) { //Obtenemos las 1000 siguientes filas y las añadimos a un array
console.log("obtain 1000 results");
console.log(data);
var rows = new Array();
data.forEach(el => {
rows.push(generaterow(el))
});
$("#GridAseguradora").jqxGrid('addrow', null, rows); // Agregamos las filas generadas anteriormente al grid
$("#GridAseguradora_contRegTotal").text("Reg. Visibles: " + $("#GridAseguradora").jqxGrid('getrows').length)
})
})(i);
}
})
}, 100);
})
The Console.logs I wanna obtain:
1-first for loop
obtain 1000 results
(append results)
2-first for loop
obtain 1000 results
(append results)
.....
What I hope is that the client sees that the products are being loaded little by little, not that the remaining 9000 are loaded together
Upvotes: 0
Views: 1356
Reputation: 998
You are immediately appending the .then()
clauses when you run your loop, hence they immediately get resolved. You essentially want to block each loop iteration until the promise resolves and then continue on to the next one and repeat.
You can do this with async / await too, but here is how you achieve synchronous loop iterations with promises:
let promise = Promise.resolve()
for (let i = 0; i < 10; i++) {
promise = promise.then(() => {
fetchData('ArticulosSearch', inputValues).then(res => {
// your logic here
})
})
}
You initialise a new promise with Promise.resolve()
and keep appending then()
s to it on each loop iterations. These .then()
will execute only when the previous one is resolved.
This will ensure things are properly scheduled one after another.
Take a look at this snippet, I tried to simulate some async operation that takes variable time to resolve:
const outputEl = document.getElementById('output')
const fetchSomethingFromDBAsyncFake = (idx) => new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
outputEl.innerHTML += `
<br />
Loaded chunk ${idx}
`
resolve()
clearTimeout(timeout)
}, 500 + Math.random() * 1750)
})
let promise = Promise.resolve()
for (let i = 0; i < 10; i++) {
promise = promise.then(() => fetchSomethingFromDBAsyncFake(i))
}
<div id="output"></div>
Upvotes: 2