0

I’m trying to use an increment loop but I want it to increment at the end of the loop. Sadly, whenever I simply put the i++ at the end of the loop it doesn’t behave like I’d expect or want it to. Anyone mind showing me the proper way of doing it?

The referred increment loop:

for (i = 1; i < 15; i++) {
  // do somthing here
}

Here is the loop I’m working with:

for (i = 1; i < 15; i++) {
  for (x = 1; x < 15; x++) {
    var take = document.getElementById("row" + i + "sm" + x);

    Tesseract.recognize(take)
      .then(function(result) {
        console.log(result.text);
        // rows[i][x] = result.text;
      })
  }
}

What I’d like it to do:

for (i = 1; i < 15) {
  for (x = 1; x < 15) {
    var take = document.getElementById("row" + i + "sm" + x);

    Tesseract.recognize(take)
      .then(function(result) {
        console.log(result.text);
        //rows[i][x] = result.text;
        x += 1;
      })
    i += 1;
  }
}

I am using the for loop because I need to iterate over something one by one. How do I properly increment i at the end of the loop?

Here is a video explaining my problem with context and explanation why it is not an ASYNC problem. Sorry if it is hard to follow, ill update it with audio soon so I can explain it propperly.

https://drive.google.com/file/d/1n1ZwNJif5Lb5zfLb2GPpBemObwpOqNf7/view

Liam Weitzel
  • 23
  • 10
  • Please can you elaborate as it is difficult to understand what your are expecting from the loops. – amrender singh Jun 22 '18 at 18:14
  • 2
    This seems like an [XY Problem](https://xyproblem.info). I think your problem is caused by the fact that you're running an asynchronous process inside a loop. – Heretic Monkey Jun 22 '18 at 18:16
  • Regarding your edit; well, your normal loop also iterates one by one. What is happening in your code that is not working the way you want, such that you want to change how a loop works? – Heretic Monkey Jun 22 '18 at 18:24
  • I'm with Mike, async in loop is a bit different... [https://blog.lavrton.com/javascript-loops-how-to-handle-async-await-6252dd3c795](https://blog.lavrton.com/javascript-loops-how-to-handle-async-await-6252dd3c795) – Brad Evans Jun 22 '18 at 18:36
  • 1
    Possible duplicate of [JavaScript closure inside loops – simple practical example](https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – Sebastian Simon Jun 22 '18 at 18:41
  • How exactly does the loop not work if you still have commented out the `rows[i][x] = result.text;` line? It just seems you’re not iterating over the full grid. It should be `for (i = 0; i <= 14; i++)` and `for (x = 0; x <= 14; x++) {` with `<=` instead of `<`. Those are not the same loops as in the question. The update statements `i++` and `x++` will _always_ be executed after a loop iteration. – Sebastian Simon Jun 22 '18 at 19:10

4 Answers4

1

The problem is that the second one doesnt wait until first one is complete.

You can try with recursion inside then. There maybe some mistake with i,x but you get the point.

You execute first with i=1 and x=1, after the operation is done (then) you call the next until all elements are executed.

function execItem(i, x) {
    var take = document.getElementById("row" + i + "sm" + x);
    Tesseract.recognize(take)
    .then(function(result){
        rows[i][x] = result.text;
        if (i < 15 && x < 15) {
            if (i > 15) {
                x += 1
                i = 1
            } else {
                i += 1
            }
            execItem(i, x)

        } 
    })
}
execItem(1, 1)
0

As a comment suggests this actually seems likely to be a problem with an asynchronous call (Tesseract...then) inside a loop. By the time the function inside then is called, your values of x and i have already moved on, so you don't get the result you expect.

One way around this would be to use a 'closure' - making a function that creates another function based on the value of i and x.

function getDisplayFunc(row, col) {
    function displayRecognisedText(result) {
      console.log(row, col, result.text);
     //rows[row][col] = result.text;
  }
  return displayRecognisedText;
}

for (i = 1; i < 15; i++) {
    for (x = 1; x < 15; x++) {
        var take = document.getElementById("row" + i + "sm" + x);
        Tesseract.recognize(take).then(getDisplayFunc(i, x));
    }
}
Stuart
  • 9,597
  • 1
  • 21
  • 30
-1

Maybe you should try to use while loop. Like this:

            while i < 15:
            //do something
            i += 1

For two variables: x, i with embeding:

            while x < 15:
                //do something
                while i < 15:
                    //do something2
                    i += 1
                x += 1

Hope I understand the problem correctly.

sipi09
  • 389
  • 4
  • 7
  • Ok, in that case you need two variable, one for i, and one for x. You have to embed one into the other. Something like this. Wait, I'll improve my answer. – sipi09 Jun 22 '18 at 18:27
  • @LiamWeitzel Every `for` loop can be rewritten as a `while` loop and vice-versa. – Sebastian Simon Jun 22 '18 at 18:38
-1

I guess @Mike spot the error on: your code is asynchronous. What does it mean?

So, let's suppose you have this loop:

for (i = 0; i < 10; i++) {
  console.log(i);
}

It will print this, right?

0
1
2
3
4
5
6
7
8
9

However, you do not print your value inside the loop directly, but as a follow-up operation to a promise. This makes this code asynchronous. It means that it does not have to execute at the exact moment you call it. I do not have Tesseract here so I will make my loop asynchronous using another very old trick, setTimeout():

for (i = 0; i < 10; i++) {
    setTimeout(function() {
      console.log(i);
    }, 0);
}

If I run it, I get this:

10
10
10
10
10
10
10
10
10
10

What happens is, when I pass the operation we want to do (in this case, printing the i value) to an asynchronous function (recognize().then() in your case, setTimeout() in my case) through a callback (function() {console.log(i);} in my example) the asynchronous function "schedules" the operation to execute as soon as possible, but this "soon" is not faster than the loop. So, the loop finishes executing but our callback is not called, not even once! Since you are not declaring i with let, it is a global variable, so there exists only one i. And since the loop finished, the value of the i variable is 10 already.

It used to be a hard thing to solve, but with ES6 it is quite straightforward: declare i with let!

for (let i = 0; i < 10; i++) {
    setTimeout(function() {
      console.log(i);
    }, 0);
}

The let-ed variable has a new binding at each iteration of the loop, so in practice you have 10 variables called i. The closure of your function will have access only to the one with the right value!

brandizzi
  • 26,083
  • 8
  • 103
  • 158
  • I do not think that it is an 'async' problem, ill upload a video explaining why in an edit. give me a minute :) 'async' is in qoutation marks because i've never heard the term before, not out of sacrasm. – Liam Weitzel Jun 22 '18 at 18:49
  • @LiamWeitzel You’re using promises (since you’re using a `then` method) which are asynchronous _by nature_. They execute later in time, when `x` and `i` have long changed their values. – Sebastian Simon Jun 22 '18 at 18:50
  • 1
    @LiamWeitzel well, maybe, we're still exploring possibilities here, but could you try declaring `i` with `let` to see if it works? – brandizzi Jun 22 '18 at 18:51
  • I tried, it didnt work, I uploaded a video outlining the problem (using let btw) – Liam Weitzel Jun 22 '18 at 19:01
  • 1
    @LiamWeitzel It does work, if you set up the loop correctly. You definitely need `let` here. In the video you’re iterating from `0` inclusive to `14` _exclusive_. Just loop up to 14 _inclusive_ by changing `<` to `<=`. This is a problem unrelated to your original code or question or problem. – Sebastian Simon Jun 22 '18 at 19:13