我试图遍历数组,但想要延迟输出数组的每个值。这就是我目前对它应该如何运作的理解:
修改
请求JS小提琴:http://jsfiddle.net/d3whkjww/
loopThroughSplittedText: function(splittedText) {
for (var i = 0; i < splittedText.length; i++) {
// for each iteration console.log a word
// and make a pause after it
setTimeout(
console.log(splittedText[i]),
1000
);
};
},
然而,它不起作用,我相信它可能是,因为&#34; for&#34;循环必须在setTimeout函数内。但我不知道如何让它发挥作用。
我得到的只是数组的每个值,但我希望它们出现延迟。我该怎么做?
答案 0 :(得分:10)
var splittedText = ["Hello", "World", "How", "Are", "You", "Today"];
function loopThroughSplittedText(splittedText) {
for (var i = 0; i < splittedText.length; i++) {
// for each iteration console.log a word
// and make a pause after it
(function (i) {
setTimeout(function () {
document.getElementById('text').innerHTML += splittedText[i];
console.log(splittedText[i]);
}, 1000 * i);
})(i);
};
}
loopThroughSplittedText(splittedText);
答案 1 :(得分:3)
在我的示例中,它将向您展示如何在您停止之前有争议地遍历数组。这是为了让您了解如何延迟。它还会显示实际显示值的时间。
我会说你实际上可以从这个计时器创建一个很好的实用程序,并将它用于多种用途,并且使用它可以阻止你重复大块代码。
JavaScript循环示例:
var body = document.body;
var splittedText = ["Hello", "World", "How", "Are", "You", "Today"];
loopThroughArray(splittedText, function (arrayElement, loopTime) {
body.innerHTML += arrayElement+ ": " + loopTime+ "<br/>";
}, 1000);
function loopThroughArray(array, callback, interval) {
var newLoopTimer = new LoopTimer(function (time) {
var element = array.shift();
callback(element, time - start);
array.push(element);
}, interval);
var start = newLoopTimer.start();
};
// Timer
function LoopTimer(render, interval) {
var timeout;
var lastTime;
this.start = startLoop;
this.stop = stopLoop;
// Start Loop
function startLoop() {
timeout = setTimeout(createLoop, 0);
lastTime = Date.now();
return lastTime;
}
// Stop Loop
function stopLoop() {
clearTimeout(timeout);
return lastTime;
}
// The actual loop
function createLoop() {
var thisTime = Date.now();
var loopTime = thisTime - lastTime;
var delay = Math.max(interval - loopTime, 0);
timeout = setTimeout(createLoop, delay);
lastTime = thisTime + delay;
render(thisTime);
}
}
答案 2 :(得分:2)
代码的一个问题是i
对所有回调都是通用的。因此,第一个回调被告知&#34;输出索引i
&#34;的条目,但是当它执行初始循环时已经完成,所以i
现在已经结束了文本。
实现您正在寻找的东西的一种方法是不使用for
循环,而是使用(1)打印字符,(2)更新计数器/位置的函数,以及(3)如果需要,安排下一个角色:
loopThroughSplitText: function (text) {
var i = 0;
function printEntry() {
console.log(text[i]);
i++; // Increment the position
if (i < text.length) { // If there are more chars, schedule another
setTimeout(printEntry, 1000);
}
}
printEntry(); // Print the first entry/char
}
答案 3 :(得分:2)
好的,因为它不是完全重复的,你需要增加循环中的延迟,也要逃避c losure variable in a loop issue
loopThroughSplittedText: function (splittedText) {
splittedText.forEach(function (text, i) {
setTimeout(function () {
console.log(text);
}, i * 1000)
})
}
var obj = {
loopThroughSplittedText: function(splittedText) {
splittedText.forEach(function(text, i) {
setTimeout(function() {
document.getElementById('x').innerHTML += text
}, i * 1000)
})
}
}
obj.loopThroughSplittedText('abcde'.split(''))
&#13;
<div id="x"></div>
&#13;
答案 4 :(得分:2)
递归函数调用可以完成这项工作:
var a = [
1,2,3,4,5,6,7,8,9,10
];
function log(i){
console.log(a[i]);
if (i<a.length){
setTimeout(function(){
i++;
log(i);
},1000);
}
}
log(0);
答案 5 :(得分:1)
另一个解决方案,使用setInterval:
var i = 0;
var intv = setInterval(function() {
if (i >= splittedText.length) {
clearInterval(intv);
} else {
console.log(splittedText[i]);
++i;
}
}, 1000);
答案 6 :(得分:1)
这里有几个问题
setTimeout
应该使用函数,而不是调用函数的结果 setTimeout
立即返回,所以你的循环中的所有动作都将在大致相同的时刻开始,所有动作都会在执行前等待1000ms(尽管有上述评论,这意味着它们都是在同一时间执行的)力矩)。i
的值对于每次迭代都将等于splittedText.length
。您需要做的是等待setTimeout
指令执行,然后再继续循环的下一次迭代。
例如:
var splittedText = ["Hello", "World", "How", "Are", "You", "Today"];
function loopThroughSplittedText(splittedText) {
displayValue(splittedText,0);
}
function displayValue(arr, i){
if(i<arr.length){
setTimeout(function(){
document.getElementById('text').innerHTML = arr[i];
console.log(arr[i])
displayValue(arr,i+1);
},1000)
}
}
loopThroughSplittedText(splittedText)
答案 7 :(得分:1)
这也可行
function loopThroughSplittedText(splittedText) {
for (var i=0; i < splittedText.length;i++) {
(function(ind, text) {
setTimeout(function(){console.log(text);}, 1000 + (1000 * ind));
})(i, splittedText[i]);
}
}
答案 8 :(得分:1)
提出问题的替代解决方案,即使用setTimeout
的第三个参数,仅在较新的浏览器中支持:
(function (splittedText) {
for (var i = 0; i < splittedText.length; i++) {
setTimeout(
function(val) { console.log(val); },
i * 1000,
splittedText[i]
);
}
})(["Hello", "world", "!"]);
&#13;
API文档可以是seen here(请注意可选参数)。
答案 9 :(得分:1)
另一个样本:
var split = 'Lorem ipsum dolor'.split(' ');
var loop = function() {
console.log(split[0]);
split = split.slice(1);
if (split.length > 0) {
setTimeout(function() {
loop();
}, 1000);
}
}
loop();
答案 10 :(得分:1)
你可能想要在这里使用递归函数而不是for循环。但是,我会解释这两种方式,以防万一你(或其他人读到这篇文章)你的心已经开始用循环来做这件事。
对于递归函数,一般的想法是你需要调用一次函数,然后让它自己重复调用,直到它完成了你想要它做的事情。在代码方面,它可能看起来像这样:
loopThroughSplittedText: function(splittedText) {
// Create our counter; delayedOutput will use this to
// track how far along in our string we are currently at
var locationInString = 0;
function delayedOutput() {
// Output the next letter in our string
console.log(splittedText[locationInString]);
// Increment our counter so that on the next call we are on the next letter
locationInString++;
// Only perform setTimeout if we still have text left to output
if (locationInString < splittedText.length) {
// Functions can reference themselves using their own name
setTimeout(delayedOutput, 1000);
}
}
// Call our function once to get things started
delayedOutput();
},
或者,如果你真的更喜欢使用一个循环,你仍然可以这样做,但是为了实现这个目的,还有一些必须要做的事情。
首先,您需要将console.log
置于其自己的功能中。这是因为当你放置console.log(something)
时,你实际上并没有传递它,而是当时正在那里调用,这不是你想要的;通过调用它,它会立即将文本吐出到控制台,而不是等到稍后。将它放在自己的函数中允许将它传递给setTimeout,以便稍后调用它。
其次,你将不得不在另一个函数中包含 函数,以确保它在激活时被赋予i
的正确值。原因实际上是这样的:你的目的是告诉函数“当你准备好时,使用我设置你的时候i
。”但是,你现在所做的就是有效地说“当你准备好了,看看i
”。因为该函数在准备好触发之前不检查i
是什么,所以直到你执行循环之后它才会知道它的值,这意味着i
将是一个远高于你的数字想!
作为上述的一个子要点,您需要立即调用该函数。这称为立即调用的函数表达式。如果你不熟悉它们,那么它们肯定值得一试。它们的用途有点不寻常,但它们在正确的位置上是一个强大的工具。
最后,因为您现在正在设置所有内容,所以您需要确保每个函数的超时时间相隔一秒;就像现在一样,你说的是“从现在开始做所有这一切”,当你的意图是“从现在起一秒钟开始所有这一秒”。这个修复相对容易;你需要做的就是将你的超时时间乘以i
,这样你就可以设置第一个从现在开始的1秒,第二个从现在起设置为2秒,依此类推。
所有这些组合为您提供了类似这样的代码:
loopThroughSplittedText: function(splittedText) {
for (var i = 0; i < splittedText.length; i++) {
setTimeout(
(function(locationInString) {
return function() {
console.log(splittedText[locationInString]);
};
}(i)),
(1000*i)
);
}
},
至于哪种解决方案更好,我可能会推荐递归函数。递归版本只会创建一个函数,为您传递的每个字符串调用自身,而for循环版本将为字符串中的每个字符创建一个函数,这可能会非常快速地失控。当您处理大型项目时,函数创建(以及一般的对象创建)在JavaScript中会变得昂贵,因此通常最好采用避免在可能的情况下创建大量函数的解决方案。
但是,为了便于解释,我不想在没有for循环版本的情况下离开你;这些知识可以在其他地方派上用场。 :)
答案 11 :(得分:1)
解决方案使用闭包 https://jsfiddle.net/x3azn/pan2oc9y/4/
function loopThroughSplittedText(splittedText) {
var splittedText = ["Hello", "World", "How", "Are", "You", "Today"];
for (var i = 0; i < splittedText.length; i++) {
// for each iteration console.log a word
// and make a pause after it
(function(_i) {
setTimeout(function() {
window.document.getElementById('text').innerHTML = splittedText[_i];
console.log(splittedText[_i]);
}, 1000)
}(i));
}
}
loopThroughSplittedText()
答案 12 :(得分:0)
您可以通过3种方式实现
1. closure
2. Recursive
3. variable declaration using let
var data = ['a','b','c','d'];
for(i=0; i<=data.length; i++) {
(function(x) {
setTimeout(() => {
console.log(x);
}, 1000)
})(data[i]);
}
for(const ind of data) {
let local = ind;
setTimeout(() => {
console.log(local);
}, 1000)
}