使用 forEach 循环执行每次迭代后添加延迟 [英] Add a delay after executing each iteration with forEach loop

查看:123
本文介绍了使用 forEach 循环执行每次迭代后添加延迟的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有一种简单的方法可以减慢 forEach 中的迭代速度(使用普通的 javascript)?例如:

Is there an easy way to slow down the iteration in a forEach (with plain javascript)? For example:

var items = document.querySelector('.item');

items.forEach(function(el) {
  // do stuff with el and pause before the next el;
});

推荐答案

使用 Array#forEach — 完全可以实现您想要实现的目标虽然你可能会以不同的方式思考它.你可以做这样的事情:

What you want to achieve is totally possible with Array#forEach — although in a different way you might think of it. You can not do a thing like this:

var array = ['some', 'array', 'containing', 'words'];
array.forEach(function (el) {
  console.log(el);
  wait(1000); // wait 1000 milliseconds
});
console.log('Loop finished.');

...并获得输出:

some
array          // one second later
containing     // two seconds later
words          // three seconds later
Loop finished. // four seconds later

JavaScript 中没有同步的 waitsleep 函数会阻止其后的所有代码.

There is no synchronous wait or sleep function in JavaScript that blocks all code after it.

在 JavaScript 中延迟某些事情的唯一方法是以非阻塞方式.这意味着使用 setTimeout或其亲属之一.我们可以使用传递给 Array#forEach 的函数的第二个参数:它包含当前元素的索引:

The only way to delay something in JavaScript is in a non–blocking way. That means using setTimeout or one of its relatives. We can use the second parameter of the function that we pass to Array#forEach: it contains the index of the current element:

var array = ['some', 'array', 'containing', 'words'];
var interval = 1000; // how much time should the delay between two iterations be (in milliseconds)?
array.forEach(function (el, index) {
  setTimeout(function () {
    console.log(el);
  }, index * interval);
});
console.log('Loop finished.');

使用index,我们可以计算函数应该何时执行.但是现在我们有一个不同的问题:console.log('Loop finished.') 在循环的第一次迭代之前 执行.那是因为 setTimout 是非阻塞的.

Using the index, we can compute when the function should be executed. But now we have a different problem: the console.log('Loop finished.') is executed before the first iteration of the loop. That's because setTimout is non–blocking.

JavaScript 在循环中设置超时,但它不会等待超时完成.它只是继续执行 forEach 之后的代码.

JavaScript sets the timeouts in the loop, but it doesn't wait for the timeouts to complete. It just continues executing the code after the forEach.

为了解决这个问题,我们可以使用 Promises.让我们建立一个承诺链:

To handle that, we can use Promises. Let's build a promise chain:

var array = ['some', 'array', 'containing', 'words'];
var interval = 1000; // how much time should the delay between two iterations be (in milliseconds)?
var promise = Promise.resolve();
array.forEach(function (el) {
  promise = promise.then(function () {
    console.log(el);
    return new Promise(function (resolve) {
      setTimeout(resolve, interval);
    });
  });
});

promise.then(function () {
  console.log('Loop finished.');
});

有一篇关于 Promise 结合 forEach/map/filter 的优秀文章="http://thecodebarbarian.com/basic-functional-programming-with-async-await.html" rel="noreferrer">这里.

There is an excellent article about Promises in conjunction with forEach/map/filter here.

如果数组可以动态更改,我会变得更棘手.在那种情况下,我认为不应该使用 Array#forEach.试试这个:

I gets trickier if the array can change dynamically. In that case, I don't think Array#forEach should be used. Try this out instead:

var array = ['some', 'array', 'containing', 'words'];
var interval = 2000; // how much time should the delay between two iterations be (in milliseconds)?

var loop = function () {
  return new Promise(function (outerResolve) {
    var promise = Promise.resolve();
    var i = 0;
    var next = function () {
      var el = array[i];
      // your code here
      console.log(el);
      if (++i < array.length) {
        promise = promise.then(function () {
          return new Promise(function (resolve) {
            setTimeout(function () {
              resolve();
              next();
            }, interval);
          });
        });
      } else {
        setTimeout(outerResolve, interval);
        // or just call outerResolve() if you don't want to wait after the last element
      }
    };
    next();
  });
};

loop().then(function () {
  console.log('Loop finished.');
});

var input = document.querySelector('input');
document.querySelector('button').addEventListener('click', function () {
  // add the new item to the array
  array.push(input.value);
  input.value = '';
});

<input type="text">
<button>Add to array</button>

这篇关于使用 forEach 循环执行每次迭代后添加延迟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆