Nested for loop,delay on each loop individually - javascript

An example of simple nested for loop:
for (let i=0; i<=2; i++) {
for (let j=0; j<=1; j++){
console.log("i is: " + i);
console.log("j is: " + j);
console.log("---");
}
}
Nested for loop with delay:
for (let i=0; i<=2; i++) {
for (let j=0; j<=1; j++){
task(i,j);
}
}
function task(i,j) {
setTimeout(function() {
console.log("i is: " + i);
console.log("j is: " + j);
console.log("---")
}, 1000 * i);
}
NOW MY QUESTION IS
How can I delay each loop seperately.
Current output (ignore the "---"):
i, j, delay, i, j, delay, ...
Desired output (ignore the "---"):
i, delay, j, delay, i, delay, j, delay ...
I tried things like below (but its returning a complete wrong output)
for (let i=0; i<=2; i++) {
for (let j=0; j<=1; j++){
taski(i);
taskj(j)
}
}
function taski(i) {
setTimeout(function() {
console.log("i is: " + i);
}, 1000 * i);
}
function taskj(j){
setTimeout(function() {
console.log("j is: " + j);
}, 1000 * j);
}

You could use Promise and async/await to handle sequential call
function taski(i) {
return new Promise(function (resolve) {
setTimeout(function () {
console.log("i is: " + i)
resolve()
}, 1000 * i)
})
}
function taskj(j) {
return new Promise(function (resolve) {
setTimeout(function () {
console.log("j is: " + j)
resolve()
}, 1000 * j)
})
}
async function execute() {
for (let i = 0; i <= 2; i++) {
for (let j = 0; j <= 1; j++) {
await taski(i)
console.log("delay")
await taskj(j)
console.log("delay")
}
}
}
execute()
Reference:
async function
Promise

Ok the thing is setTimeout works in it's own world that isn't limited by the for loops, or any other code for that matter, it doesn't actually "block" the current code at all, in the for loop you are just setting up a bunch of intervals, really fast one after the other (since the for loop doesn't stop or get delayed by the timeouts), which later execute in some unknown order when the time for each one individually runs out, which is not blocked or dependant on any of the other timeouts
If you want to keep relatively the same format you have now, but with delay blocking you can use await and promises and async functions
(async () =>
for (let i=0; i<=2; i++) {
for (let j=0; j<=1; j++){
await taski(i);
await taskj(j)
}
}
)()
function taski(i) {
return new Promise((rs) => setTimeout(function() {
res(console.log("i is: " + i));
}, 1000 * i));
}
function taskj(j){
return new Promise((rs) => setTimeout(function() {
res(console.log("j is: " + j)
}, 1000 * j));
}

You could try to to an asynchronous approach with async/await:
function sleep(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
(async function() {
for (let i = 0; i <= 2; i++) {
for (let j = 0; j <= 1; j++) {
await taski(i);
await taskj(j);
}
}
}())
async function taski(i) {
await sleep(1000 * i);
console.log("i is: " + i);
}
async function taskj(j) {
await sleep(1000 * j);
console.log("j is: " + j);
}

Related

For-loop that is skipping even count

I have a small for loop, but it is skipping even count , what am I missing ?
var i = 0;
function myLoop() {
setTimeout(function() {
//code below
console.log(Date() + ' and count is ' + i++);
//code above
if (i < 20) {
myLoop();
}
}, i++)
}
myLoop()
i++ is equal i = i + 1; But when you call console.log(i++), first thing wil be console.log with Old value, and after increment your value.
You raise the timeout with every iteration by on millisecond. Is that what you wanted?
https://www.w3schools.com/jsref/met_win_settimeout.asp
setTimeout(function, milliseconds, param1, param2, ...)
var i = 0;
function myLoop() {
setTimeout(function() {
//code below
console.log(Date() + ' and count is ' + i++);
//code above
if (i < 20) {
myLoop();
}
}, 1)
}
myLoop()
Your i++ in the console.log statement is modifying your i variable.
i++ is equal to i = i + 1.
Replace i++ with i, which will evaluate correctly as postfix increment will return the value before the modification which would just be i.
This works:
var i = 0;
function myLoop() {
setTimeout(function() {
//code below
console.log(Date() + ' and count is ' + i);
//code above
if (i < 20) {
myLoop();
}
}, i++)
}
myLoop()
Can also be done by adding another variable for the console.log
var i = 0;
var t = 0;
function myLoop() {
setTimeout(function() {
//code below
console.log(Date() + ' and count is ' + t++);
//code above
if (t < 20) {
myLoop();
}
}, i++)
}
myLoop()
You have i++ twice in your code. First you increment it when you call setTimeout at the bottom of your code and then you display the uneven value via console log and increment i. Change your logging to
console.log(Date() + ' and count is ' + i);

Pause a function in jQuery or JavaScript [duplicate]

This question already has answers here:
JavaScript Loop and wait for function
(2 answers)
Closed 2 years ago.
I want to stop this function for a few seconds while adding every digit,
but this function doesn't work as intended.
function yazmaeffetkti() {
var cumleler = ["salam necesen", "yaxsiyam sen "]
currentcumle = ""
for (var i = 0; i < cumleler.length; i++) {
cumle = cumleler[i]
for (var z = 0; z < cumle.length; z++) {
currentcumle += cumle[z]
function stateChange(currentcumle) {
setTimeout(function() {
console.log(currentcumle);
}, 3000);
}
stateChange(currentcumle)
}
currentcumle = ""
}
}
yazmaeffetkti()
The cleanest way to achieve that is to use async and await:
async function yazmaeffetkti() {
// ...
await new Promise(resolve => setTimeout(resolve, 3000));
console.log(currentcumle);
// ...
}
here is my version:
async function yazmaeffetkti() {
var cumleler = ["salam necesen", "yaxsiyam sen "]
currentcumle = ""
for (var i = 0; i < cumleler.length; i++) {
cumle = cumleler[i]
for (var z = 0; z < cumle.length; z++) {
currentcumle += cumle[z]
await stateChange(currentcumle)
}
currentcumle = ""
}
}
var stateChange = (currentcumle) => new Promise((resolve)=>{
setTimeout(function() {
console.log(currentcumle);
resolve(true);
}, 1000);
});
yazmaeffetkti()
In addition to Robo Robok's answer, here is an example using the same concept but with then instead of async/await. I personnaly prefer it but it's up to you.
function yazmaeffetkti() {
var cumleler = ["salam necesen", "yaxsiyam sen "]
currentcumle = ""
for (var i = 0; i < cumleler.length; i++) {
cumle = cumleler[i]
for (var z = 0; z < cumle.length; z++) {
currentcumle += cumle[z]
new Promise(resolve => setTimeout(resolve, 3000)).then(() => {
console.log(currentcumle);
});
}
currentcumle = ""
}
}
yazmaeffetkti()

Uncaught (in promise):How to await a function which returns a promise inside a loop?

I am working on awaiting a function that returns a promise inside a loop. But, I was not able to resolve it.
the loop is
for (var i = 0; i < rows.length; i++) {
console.log("row " + i);
getData(i).then(function (data) {
console.log("data of row "+ i +" is "+ data);
});
}
The output is:
row 0
row 1
row 2
data of row undefined data
data of row undefined data
data of row undefined data
i've tried to put the loop in a Async Context and await for the getData function but it causes deadlock with the error of Uncaught (in promise) undefined at row 0 like below:
getRows().then(async function (rows) {
for (var i = 0; i < rows.length; i++) {
console.log("row " + i);
await getData(i).then(function (data) {
console.log("data of row "+ i +" is "+ data);
});
}
});
Of worth to say, i'v defined promise reject function like this:reject(undefined) but i'v tried reject(false) and reject(null) also. However, No difference and Uncaught (in promise) exception throws and deadlock happens.
function getData(row) {
var promise = new Promise(function (resolve, reject) {
whenAvailable("read", function (t) {
read("data", row, 0, 1, true, "so").then(function (data) {
if (data != undefined) {
resolve(data);
} else {
reject(false);
}
});
});
});
return promise;
}
and also i'v check other stackoverflow related question but they were not suitable for my problem.
Can you help me overcome this problem?
Update
i did below as #SunilLama said
getRows().then(async function (rows) {
if (rows != undefined) {
for (var i = 0; i < rows.length; i++) {
console.log("rows " + i);
await getData(i).then(function (data) {
console.log(data);
}, error => console.log(error));
}
}
again deadlock with exception of
wrapping the loop in an async function should do it:
function getData(i) {
var promise= new Promise((resolve, reject) => {
setTimeout(function() {
resolve(i+1);
},1000);
});
return promise;
}
var main = async() => {
for (var i = 0; i < 10; i++) {
console.log("row " + i);
await getData(i).then(function(data) {
console.log("data of row " + i + " is " + data);
},error=> console.log(error));
}
}
main();
If your point is that each iteration should wait previous one, then one way is to do it with recursion.
var rows = ["a","b","c"];
function getData(i) {
var promise= new Promise((resolve, reject) => {
setTimeout(function() {
resolve(rows[i]);
},1000);
});
return promise;
}
function recur(i) {
i = i || 0; // For first time, makes it zero
if (i >= rows.length) { return; } // Stop if it's out of range
console.log("row " + i);
getData(i).then(function (data) {
console.log("data of row "+ i +" is "+ data);
recur(i + 1); // Call for next iteration
});
}
recur(); // Call

Delay in for loop breaks function

I need to create a small delay in this for loop:
for (i = 1; i <= cloneIndex; i++) {
var myElem = document.getElementById('form' + i);
if (myElem != null) {
function postData() {
return {
udd: document.getElementById('udd').value,
data: date_in,
hora_ini: hour_in,
hora_fim: hour_out,
cat: $('#form' + i).find('select[id="cat"]').val(),
m1: $('#form' + i).find('select[id="q1"]').val(),
m2: $('#form' + i).find('select[id="q2"]').val(),
m3: $('#form' + i).find('select[id="q3"]').val(),
m4: $('#form' + i).find('select[id="q4"]').val(),
m5: $('#form' + i).find('select[id="q5"]').val()
}
}
var newItem = postData();
$2sxc(#Dnn.Module.ModuleID).webApi.post('app/auto/content/audits', {}, newItem);
}
}
Following stackoverflow examples, I tried this solution:
for (i = 1; i <= cloneIndex; i++) {
(function(i){
setTimeout(function(){
var myElem = document.getElementById('form' + i);
if (myElem != null) {
function postData() {
return {
udd: document.getElementById('udd').value,
data: date_in,
hora_ini: hour_in,
hora_fim: hour_out,
cat: $('#form' + i).find('select[id="cat"]').val(),
m1: $('#form' + i).find('select[id="q1"]').val(),
m2: $('#form' + i).find('select[id="q2"]').val(),
m3: $('#form' + i).find('select[id="q3"]').val(),
m4: $('#form' + i).find('select[id="q4"]').val(),
m5: $('#form' + i).find('select[id="q5"]').val()
}
}
var newItem = postData();
$2sxc(Dnn.Module.ModuleID).webApi.post('app/auto/content/audits', {}, newItem);
}
}, 1000 * i);
}(i));
}
However this breaks the function inside. It seems myElem is now always null. Too many "i"s? How can I fix this?
You need to define the variable inside the closure for it to be unique to each iteration:
for (var i = 1; i < 10; i++) {
(function() {
var k = i; // <-- k will be different for each iteration, because it was declared inside the closure. i was defined outside the closure.
setTimeout(function() {
console.log("Delayed: ", i, k)
}, i * 1000)
}());
}
...or else include i in the closure definition:
for (var i = 1; i < 10; i++) {
(function(i) {
setTimeout(function() {
console.log("Delayed: ", i)
}, i * 1000)
}(i));
}
Nevermind. The reason the code did not work was simple. The rest of the code below did not wait for the delayed loop to end, so it actually broke the function.
This fixed it (placed inside the setTimeout function):
k++;
if (k == cloneIndex) {rest of the code that needs the loop to end}

How to print the items in q, the async way

Here is a program i'm trying wrap my head around with, how do i print the items in the q properly, once all the results are pushed ?
function asyncAdd(a,b,callback) {
setTimeout(function() {
return callback(a+b);
},0);
}
var q = [];
var ctr = 0;
for (var i=0; i<9; i++) {
(function(i) {
var res = asyncAdd(i, 0, printRes);
q.push(res);
})(i);
}
function done(q) {
console.log("done"+q);
}
function printRes(res) {
return res;
}
Please have a look at my version
function asyncAdd(a,b,callback) {
callback(a+b);
}
var q = [];
var ctr = 0;
var max = 9;
for (var i = 0; i < max; i++) {
asyncAdd(i, 0, printRes);
}
function done(q) {
console.log("done " + q);
}
function printRes(res) {
q.push(res);
if (q.length === max)
done(q);
}

Categories

Resources