requestAnimationFrame(callback) 与 for 循环问题

requestAnimationFrame(callback) with for loop issue

最近我发现 JavaScript 的 requestAnimationFrame(callback) 方法有一个奇怪的问题。这是我的代码:

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);
}

在我的预期中,控制台中应该有如下循环:

  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

但实际上,控制台日志是这样的:

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

我应该怎么做才能使用 for 循环和 requestAnimationFrame() 获得预期结果?

window.requestAnimationFrame是一个异步函数,对于i从0到2,你初始化三个外window.requestAnimationFrame任务;

经过第3个外window.requestAnimationFrame任务,i从0变为2,并且flag递增为3;

目前,i 是 2,标志是 3,你在每个内部 window.requestAnimationFrame 回调中都有一个 if 条件 if (flag < 5),所以内部回调只有 运行 两次(对于 flag = 4,flag = 5)i 总是 2.

我修改代码:

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);
}

为什么不直接使用 ES6 的 let 来简化这项工作:

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

以上给出了想要的结果。

ES5 解决方案

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);
}