我试图循环一个数组,但想要延迟输出数组的每个值.这就是我目前对它应该如何工作的理解:
编辑
请求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
);
};
},
Run Code Online (Sandbox Code Playgroud)
然而,它不起作用,我相信它可能是,因为"for"循环中的参数必须在setTimeout函数内.但我不知道如何使它发挥作用.
我得到的只是数组的每个值,但我希望它们出现延迟.我怎么做?
Jas*_*ant 11
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);
Run Code Online (Sandbox Code Playgroud)
小智 8
您可能会想在这里使用递归函数而不是 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();
},
Run Code Online (Sandbox Code Playgroud)
或者,如果您确实更喜欢使用循环,您仍然可以这样做,但是需要做一些调整才能完成此操作。
首先,您需要将其放置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)
);
}
},
Run Code Online (Sandbox Code Playgroud)
至于哪种解决方案更好,我可能会推荐递归函数。递归版本只会创建一个函数,该函数会为传递给它的每个字符串调用自身,而 for 循环版本将为字符串中的每个字符创建一个函数,这可能很快就会失控。当您处理大型项目时,JavaScript 中的函数创建(以及一般的对象创建)可能会变得昂贵,因此通常最好采用尽可能避免创建大量函数的解决方案。
但是,为了解释起见,我不想让您没有 for 循环版本;这些知识可以在其他地方派上用场。:)
递归函数调用可以完成这项工作:
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);
Run Code Online (Sandbox Code Playgroud)
http://jsfiddle.net/Curt/rjve4whe/1/
在我的示例中,它将向您展示如何有争议地循环遍历数组,直到停止。这只是为了让您了解如何进行延迟。它还会向您显示该值实际显示的时间。
我想说,您实际上可以从这个计时器创建一个很好的实用程序,并将其用于多种目的,并且使用该实用程序,它将阻止您重复大块代码。
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);
}
}Run Code Online (Sandbox Code Playgroud)