ForEach(プレーンのJavaScript)で反復を遅くする簡単な方法はありますか?例えば:
var items = document.querySelector('.item');
items.forEach(function(el) {
// do stuff with el and pause before the next el;
});
あなたが達成したいことは_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
またはその親族の1つを使用します。 _Array#forEach
_に渡す関数の2番目のパラメーターを使用できます。これには、現在の要素のインデックスが含まれます。
_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.')
は、ループの最初の反復の前にbefore実行されます。これは、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
/forEach
/map
と組み合わせたfilter
sに関する優れた記事があります 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>
_
遅延を作成し、再帰的に実装するには、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)
再帰が最も簡単な解決策を提供すると思います。
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
これにより、リスト内の次のイテレーションにいつアクセスするかを完全に制御できます。
_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});
};
})();
_