3

I followed the answer to this post, however, this doesn't seem to work for me. I have a first 2 dimensional array, I want to timeout between every outer loop and not timeout in the outer loop.

Here's a snippet of this Fiddle showing one of the three ways I tried, from the aforementioned question as well as this one (cf. case 1, 2 and 3).

    var data = [
                [
                    ["data[0][0]"],  
                    ["data[0][1]"]
                ],
                [
                    ["data[1][0]"],
                    ["data[1][1]"]
                ],
                [
                    ["data[2][0]"],
                    ["data[2][1]"]
                ]
            ];	

    var delay = 1000;
    
        function doSomething(i) {
    	setTimeout(function() {
      	for(let j = 0; j < data[i].length; j++) {
        console.log(data[i][j]);
        $('#result').html($('#result').html() + data[i][j]);
        }
      }, delay);
    }
    
    for(let i = 0; i < data.length; i++) {
    	doSomething(i);
    }
    <script src="http://code.jquery.com/jquery-1.9.1.js"></script>
    <div id="result"></div>

More questions/answers on the subject tend to yield the same result so I am at a loss.

2
  • What is it doing differently than you would expect? Is it because all the setTimeouts are completing at roughly the same time, after about a second? Commented Feb 25, 2019 at 21:42
  • 1
    @David784 I want it to do [0][0] + [0][1], then after a second, [1][0] + [1][1] and after another second [2][0] + [2][1]. So a delay between each "i loops" and no delay between "j loops". Commented Feb 25, 2019 at 21:44

2 Answers 2

2

The problem is in how the setTimeout works. It's not a sleep command where it stops the for loop. Rather, it is blazing through the initial for loop, and starting three timers at roughly the same time, to last for one second each. That means they also all end at about the same time.

You can get your desired outcome by doing something more like this (notice the i*delay for the timer on the setTimeout. That way your first timer is for 0ms, second for 1000ms, third for 2000ms, and you get the staggered results you're after.

var data = [
  [
    ["data[0][0]"],
    ["data[0][1]"]
  ],
  [
    ["data[1][0]"],
    ["data[1][1]"]
  ],
  [
    ["data[2][0]"],
    ["data[2][1]"]
  ]
];

var delay = 1000;

function doSomething(i) {
  setTimeout(function () {
    for (let j = 0; j < data[i].length; j++) {
      console.log(data[i][j]);
      $('#result').html($('#result').html() + data[i][j]);
    }
  }, i*delay);
}

for (let i = 0; i < data.length; i++) {
  doSomething(i);
}
    <script src="http://code.jquery.com/jquery-1.9.1.js"></script>
    <div id="result"></div>

Sign up to request clarification or add additional context in comments.

4 Comments

This *i fix makes sense indeed, i hate myself for not trying that. However, why do all those answers I found not use that even though it's the exact same setup? And they are marked as solution.
The first answer in this: stackoverflow.com/questions/32949066/… does pretty much exactly what David is doing.
There are so many duplicates of this, I lost track. And i'm adding to the pile. :(
No worries...some of those other questions seemed to have more of a focus on the old var hoisting issue. Sometimes it's nice to have different questions with narrower focuses...so I wouldn't think of it as clutter :-)
2

Another solution for this problem (using a recursive idea) is to implement a method that call to itself every 1 second until reach the last iteration (break condition), when the index of the outter array is equal to his length:

var data = [
  [["data[0][0]"], ["data[0][1]"]],
  [["data[1][0]"], ["data[1][1]"]],
  [["data[2][0]"], ["data[2][1]"]]
];

function doSomething(i, delay)
{
    // Break condition.

    if (i >= data.length)
        return;

    // Print the inner array.

    data[i].forEach(x =>
    {
        console.log(x);
        $('#result').html($('#result').html() + x);
    });

    // Call to itself after some time to execute next iteration.

    setTimeout(() => doSomething(i + 1, delay), delay);
}

// Start the procedure.

doSomething(0, 1000);
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<div id="result"></div>

1 Comment

That is a good solution, I tried to wrap my brain around doing exactly that, but the double loop messed up my thought process for the recursion.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.