1

Recently I find a strange issue with JavaScript's requestAnimationFrame(callback) method. This is my code:

var callback = undefined;
for (var i = 0; i < 3; i++) {
  var flag = 0;
  callback = (function (index) {
    return function () {
      if (flag < 5) {
        flag++;
        console.log('K  i=' + index + ' flag=' + flag);
        window.requestAnimationFrame(callback);
      }
    }
  })(i);
  window.requestAnimationFrame(callback);
}

In my expected, there should loop as following in console:

  K  i=0   flag=1
  K  i=0   flag=2
  K  i=0   flag=3
  K  i=0   flag=4
  K  i=0   flag=5
  K  i=1   flag=1
  K  i=1   flag=2
  K  i=1   flag=3
  K  i=1   flag=4
  K  i=1   flag=5
  K  i=2   flag=1
  K  i=2   flag=2
  K  i=2   flag=3
  K  i=2   flag=4
  K  i=2   flag=5

But in fact, the console log as these:

K  i=0   flag=1
K  i=1   flag=2
K  i=2   flag=3
K  i=2   flag=4
K  i=2   flag=5

What should I do to get my expected result using for loop and requestAnimationFrame()?

abagshaw
  • 6,162
  • 4
  • 38
  • 76
  • What's that thing with `index` and `i`? – Bergi Aug 23 '17 at 02:12
  • Is there a reason you're not just doing a nested for loop to get your expected result? – TW80000 Aug 23 '17 at 02:12
  • @Bergi Emmm... Allright, as you can see, in this example, `index` and `i` is a parameter needed in callback function. – RyougiShiki Aug 23 '17 at 02:23
  • @RyougiShiki But why don't you just use `console.log('K i=' + i + ' flag=' + flag);` and get rid of the function with the `index` parameter? Can you explain what this construct does? – Bergi Aug 23 '17 at 02:25
  • @TW80000 When a animation is required, I want to use requestAnimationFrame to achieve it, and `i` and `flag` as parameters in my code operation. – RyougiShiki Aug 23 '17 at 02:27

2 Answers2

1

The window.requestAnimationFrame is a asynchronous function, for i from 0 to 2, you initialize three outer window.requestAnimationFrame task;

After the first three outer window.requestAnimationFrame task, the i from 0 to 2, and the flag increment to 3;

At the moment, the i is 2, the flag is 3, you have a if condition if (flag < 5) in every inner window.requestAnimationFrame callback , so the inner callback only run twice(for flag = 4,flag = 5)and the i is always 2.

I modify the code:

for (var i = 0; i < 3; i++) {
(function (index) {
    var flag = 0;
    var callback = function () {
        if (flag < 5) {
            flag++;
            console.log('K  i=' + index + ' flag=' + flag);
            window.requestAnimationFrame(callback);
        }
    }
    window.requestAnimationFrame(callback);
})(i);
}
JiangangXiong
  • 2,326
  • 1
  • 12
  • 14
1

Why not just use ES6's let to make this job easier:

for (let i = 0; i < 3; i++) {
 for (let flag = 0; flag < 5; flag++) {
  window.requestAnimationFrame(() => console.log('K  i=' + i + ' flag=' + flag))
  }
}

The above gives the desired results.

ES5 Solution

function loop1 (i) {
function loop2 (flag) {
  window.requestAnimationFrame(function () {
   return console.log('K  i=' + i + ' flag=' + flag);
  });
 };

 for (var flag = 0; flag < 5; flag++) {
  loop2(flag);
 }
};

for (var i = 0; i < 3; i++) {
 loop1(i);
}
Steven Scaffidi
  • 2,280
  • 1
  • 12
  • 14