在使用 forEach 循环执行每次迭代后添加延迟
Add a delay after executing each iteration with forEach loop
有没有一种简单的方法可以减慢 forEach 中的迭代速度(使用普通 javascript)?例如:
var items = document.querySelector('.item');
items.forEach(function(el) {
// do stuff with el and pause before the next el;
});
您需要使用 setTimeout 来创建延迟并进行递归实现
你的例子应该是这样的
var items = ['a', 'b', 'c']
var i = 0;
(function loopIt(i) {
setTimeout(function(){
// your code handling here
console.log(items[i]);
if(i < items.length - 1) loopIt(i+1)
}, 2000);
})(i)
首先你必须改变你的代码:
var items = document.querySelectorAll('.item'), i;
for (i = 0; i < items.length; ++i) {
// items[i] <--- your element
}
You can loop over Arrays easily in JavaScript with forEach, but
unfortunately, it's not that simple with the results of a
querySelectorAll
了解更多信息 here
我可以建议您阅读这篇文章answer,找到正确的睡眠解决方案
您可以使用 async/await
、Promise
构造函数、setTimeout()
和 for..of
循环按顺序执行任务,其中可以设置 duration
执行任务
(async() => {
const items = [{
prop: "a",
delay: Math.floor(Math.random() * 1001)
}, {
prop: "b",
delay: 2500
}, {
prop: "c",
delay: 1200
}];
const fx = ({prop, delay}) =>
new Promise(resolve => setTimeout(resolve, delay, prop)) // delay
.then(data => console.log(data)) // do stuff
for (let {prop, delay} of items) {
// do stuff with el and pause before the next el;
let curr = await fx({prop, delay});
};
})();
我认为递归提供了最简单的解决方案。
function slowIterate(arr) {
if (arr.length === 0) {
return;
}
console.log(arr[0]); // <-- replace with your custom code
setTimeout(() => {
slowIterate(arr.slice(1));
}, 1000); // <-- replace with your desired delay (in milliseconds)
}
slowIterate(Array.from(document.querySelector('.item')));
function* elGenLoop (els) {
let count = 0;
while (count < els.length) {
yield els[count++];
}
}
// This will also work with a NodeList
// Such as `const elList = elGenLoop(document.querySelector('.item'));`
const elList = elGenLoop(['one', 'two', 'three']);
console.log(elList.next().value); // one
console.log(elList.next().value); // two
console.log(elList.next().value); // three
这使您可以完全控制何时访问列表中的下一个迭代。
使用 Array#forEach
完全可以实现您想要实现的目标 — 尽管您可能会以不同的方式想到它。你可以不做这样的事情:
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 中没有同步 wait
或 sleep
函数阻塞其后的所有代码。
在 JavaScript 中延迟某些事情的唯一方法是采用非阻塞方式。这意味着使用 setTimeout
或其亲戚之一。我们可以使用传递给 Array#forEach
的函数的第二个参数:它包含当前元素的索引:
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
是非阻塞的。
JavaScript 在循环中设置超时,但它不会等待超时完成。它只是继续执行 forEach
.
之后的代码
为了处理这个问题,我们可以使用 Promise
s。让我们构建一个承诺链:
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
s 的优秀文章与 forEach
/map
/filter
here.
如果数组可以动态变化,我会变得更棘手。在那种情况下,我认为 Array#forEach
不应该被使用。试试这个:
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>
您可以做出承诺并将其与 for 一起使用,示例必须在 async / await 函数中:
let myPromise = () => new Promise((resolve, reject) => {
setTimeout(function(){
resolve('Count')
}, 1000)
})
for (let index = 0; index < 100; index++) {
let count = await myPromise()
console.log(`${count}: ${index}`)
}
使用 JS Promises 和 asnyc/await
语法,您可以创建一个真正有效的 sleep
函数。但是,forEach
会同步调用每个迭代,因此您会延迟 1 秒,然后会同时调用所有项目。
const items = ["abc", "def", "ghi", "jkl"];
const sleep = (ms) => new Promise((res) => setTimeout(res, ms));
items.forEach(async (item) => {
await sleep(1000);
console.log(item);
});
我们可以做的是使用 setInterval
和 clearInterval
(或 setTimeout
但我们使用前者)来制作一个定时 forEach 循环,如下所示:
function forEachWithDelay(array, callback, delay) {
let i = 0;
let interval = setInterval(() => {
callback(array[i], i, array);
if (++i === array.length) clearInterval(interval);
}, delay);
}
const items = ["abc", "def", "ghi", "jkl"];
forEachWithDelay(items, (item, i) => console.log(`#${i}: ${item}`), 1000);
有没有一种简单的方法可以减慢 forEach 中的迭代速度(使用普通 javascript)?例如:
var items = document.querySelector('.item');
items.forEach(function(el) {
// do stuff with el and pause before the next el;
});
您需要使用 setTimeout 来创建延迟并进行递归实现
你的例子应该是这样的
var items = ['a', 'b', 'c']
var i = 0;
(function loopIt(i) {
setTimeout(function(){
// your code handling here
console.log(items[i]);
if(i < items.length - 1) loopIt(i+1)
}, 2000);
})(i)
首先你必须改变你的代码:
var items = document.querySelectorAll('.item'), i;
for (i = 0; i < items.length; ++i) {
// items[i] <--- your element
}
You can loop over Arrays easily in JavaScript with forEach, but unfortunately, it's not that simple with the results of a querySelectorAll
了解更多信息 here
我可以建议您阅读这篇文章answer,找到正确的睡眠解决方案
您可以使用 async/await
、Promise
构造函数、setTimeout()
和 for..of
循环按顺序执行任务,其中可以设置 duration
执行任务
(async() => {
const items = [{
prop: "a",
delay: Math.floor(Math.random() * 1001)
}, {
prop: "b",
delay: 2500
}, {
prop: "c",
delay: 1200
}];
const fx = ({prop, delay}) =>
new Promise(resolve => setTimeout(resolve, delay, prop)) // delay
.then(data => console.log(data)) // do stuff
for (let {prop, delay} of items) {
// do stuff with el and pause before the next el;
let curr = await fx({prop, delay});
};
})();
我认为递归提供了最简单的解决方案。
function slowIterate(arr) {
if (arr.length === 0) {
return;
}
console.log(arr[0]); // <-- replace with your custom code
setTimeout(() => {
slowIterate(arr.slice(1));
}, 1000); // <-- replace with your desired delay (in milliseconds)
}
slowIterate(Array.from(document.querySelector('.item')));
function* elGenLoop (els) {
let count = 0;
while (count < els.length) {
yield els[count++];
}
}
// This will also work with a NodeList
// Such as `const elList = elGenLoop(document.querySelector('.item'));`
const elList = elGenLoop(['one', 'two', 'three']);
console.log(elList.next().value); // one
console.log(elList.next().value); // two
console.log(elList.next().value); // three
这使您可以完全控制何时访问列表中的下一个迭代。
使用 Array#forEach
完全可以实现您想要实现的目标 — 尽管您可能会以不同的方式想到它。你可以不做这样的事情:
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 中没有同步 wait
或 sleep
函数阻塞其后的所有代码。
在 JavaScript 中延迟某些事情的唯一方法是采用非阻塞方式。这意味着使用 setTimeout
或其亲戚之一。我们可以使用传递给 Array#forEach
的函数的第二个参数:它包含当前元素的索引:
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
是非阻塞的。
JavaScript 在循环中设置超时,但它不会等待超时完成。它只是继续执行 forEach
.
为了处理这个问题,我们可以使用 Promise
s。让我们构建一个承诺链:
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
s 的优秀文章与 forEach
/map
/filter
here.
如果数组可以动态变化,我会变得更棘手。在那种情况下,我认为 Array#forEach
不应该被使用。试试这个:
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>
您可以做出承诺并将其与 for 一起使用,示例必须在 async / await 函数中:
let myPromise = () => new Promise((resolve, reject) => {
setTimeout(function(){
resolve('Count')
}, 1000)
})
for (let index = 0; index < 100; index++) {
let count = await myPromise()
console.log(`${count}: ${index}`)
}
使用 JS Promises 和 asnyc/await
语法,您可以创建一个真正有效的 sleep
函数。但是,forEach
会同步调用每个迭代,因此您会延迟 1 秒,然后会同时调用所有项目。
const items = ["abc", "def", "ghi", "jkl"];
const sleep = (ms) => new Promise((res) => setTimeout(res, ms));
items.forEach(async (item) => {
await sleep(1000);
console.log(item);
});
我们可以做的是使用 setInterval
和 clearInterval
(或 setTimeout
但我们使用前者)来制作一个定时 forEach 循环,如下所示:
function forEachWithDelay(array, callback, delay) {
let i = 0;
let interval = setInterval(() => {
callback(array[i], i, array);
if (++i === array.length) clearInterval(interval);
}, delay);
}
const items = ["abc", "def", "ghi", "jkl"];
forEachWithDelay(items, (item, i) => console.log(`#${i}: ${item}`), 1000);