setTimeout inside for loop
我想要一个字符串出现字符转换为以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 | function initText() { var textScroller = document.getElementById('textScroller'); var text = 'Hello how are you?'; for(c = 0; c < text.length; c++) { setTimeout('textScroller.innerHTML += text[c]', 1000); } } window.onload = initText; |
它不起作用..我做错了什么?
尝试这样的事情:
1 2 3 4 5 6 7 8 9 10 11 12 13 | function initText() { var textScroller = document.getElementById('textScroller'); var text = 'Hello how are you?'; var c = 0; var interval = setInterval(function() { textScroller.innerHTML += text[c]; c++; if(c >= text.length) clearInterval(interval); }, 1000); } |
注意我添加
目前,您正在定义18个超时,所有将立即执行。
第二个问题是,您将指令作为String传递。在这种情况下,代码将无法访问initText中定义的所有变量,因为已评估的代码将在全局范围内执行。
IMO,这应该做的工作
1 2 3 4 5 6 7 8 9 10 11 12 13 | function initText(){ var textScroller = document.getElementById('textScroller'); var text = 'Hello how are you?'; var c = 0; (function(){ textScroller.innerHTML += text.charAt(c++); if(text.length > c){ setTimeout(arguments.callee, 1000); } })(); } |
甚至比@ yauhen-yakimovich回答更通用:
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | var repeat = (function () { return function repeat(cbWhileNotTrue, period) { /// <summary>Continuously repeats callback after a period has passed, until the callback triggers a stop by returning true. Note each repetition only fires after the callback has completed. Identifier returned is an object, prematurely stop like `timer = repeat(...); clearTimeout(timer.t);`</summary> var timer = {}, fn = function () { if (true === cbWhileNotTrue()) { return clearTimeout(timer.t); // no more repeat } timer.t = setTimeout(fn, period || 1000); }; fn(); // engage return timer; // and expose stopper object }; })(); |
使用
1 2 3 4 5 6 7 8 9 10 | var loop = (function () { return function loop(cbWhileNotTrue, period) { /// <summary>Continuously performs a callback once every period, until the callback triggers a stop by returning true. Note that regardless of how long the callback takes, it will be triggered once per period.</summary> var timer = setInterval(function () { if (true === cbWhileNotTrue()) clearInterval(timer); }, period || 1000); return timer; // expose stopper }; })(); |
注释中指示的两者之间略有差异 -
用法:
就像@ soufiane-hassou的回答一样:
1 2 3 4 5 6 7 8 9 | var textScroller = document.getElementById('textScroller'); var text = 'Hello how are you?'; var c = 0; var interval = repeat/* or loop */(function() { textScroller.innerHTML += text[c]; c++; return (c >= text.length); }, 1000); |
如上所述,过早停止将是:
1 2 | /* if repeat */ clearTimeout(interval.t); /* if loop */ clearInterval(interval); |
试试这个:
1 2 3 4 5 6 7 8 9 10 11 12 | function initText() { var textScroller = document.getElementById('textScroller'); var text = 'Hello how are you?'; for(c = 0; c < text.length; c++) { setTimeout("textScroller.innerHTML += '" + text[c] +"'", 1000 + c*200); } } window.onload = initText; |
我想分享一个片段(根据Soufiane Hassou的回答)。它延伸到这样一种情况,即你在一个固定的时间间隔内替换一个for循环体来迭代某个数组。基本相同的同步循环,但"睡眠"暂停(因为javascript不是同步编程语言)。
1 2 3 4 5 6 7 8 | function loop(arr, take, period) { period = period || 1000; var i = 0; var interval = setInterval(function() { take(i, arr[i]); if (++i >= arr.length) { clearInterval(interval);} }, period); } |
用法示例:
1 2 3 | loop([1, 2, 3, 4], function(index, elem){ console.log('arr[' + index + ']: ' + elem); }); |
在Node JS中测试过。希望能帮助别人。
编辑>
以下更新使代码可以与libs一起使用繁重的"原型设计"(如jQuery或原型):
1 2 3 4 5 6 7 8 9 10 11 12 13 | function loop(arr, take, period) { period = period || 1000; var scope = { i: 0, arr: arr, take: take, }; var iterate = (function iterate() { if (this.i >= this.arr.length) { clearInterval(this.interval); return} take(this.i, this.arr[this.i++]); }).bind(scope); scope.interval = setInterval(iterate, period); } |
尝试使用闭包:
1 2 3 4 5 6 7 8 9 10 11 12 | function init() { var textScroller = document.getElementById('textScroller'); var text = 'Hello how are you?'; var c = 0; function run() { textScroller.innerHTML += text[c++]; if (c<text.length) setTimeout(run, 1000); } setTimeout(run, 1000); } init() |
您的代码中的问题是您放入字符串的代码将在全局上下文中运行,其中未定义textScroller(它在您的函数内定义)。
可能更好地循环级联。例如淡化div:
1 2 3 4 5 6 7 8 | div=document.createElement('div'); div.style.opacity=1; setTimeout(function(){fade(1);},3000); function fade(op){ op-=.05; if(op>0) setTimeout(function(){div.style.opacity=op;fade(op);},30); else document.body.removeChild(div); } |
如果你想保留setTimeOut(而不是setInterval)并使用命名函数(而不是在setTimeOut调用中评估代码块),那么这可能会有所帮助:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | var b = { textScroller: document.getElementById('textScroller'), text:"Hello how are you?" }; function initText() { for(c = 0; c < b.text.length; c++) { setTimeout("append("+c+")", 1000 + c*200); } } function append(c) { b.textScroller.innerHTML += b.text[c]; } window.onload = initText; |
通过上面的内容,您可以将参数传递给追加函数。
要传递几个参数,下一个代码可以解决问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | var glo = []; function initText() { var textScroller = document.getElementById('textScroller'); var text ="Hello how are you?"; var timeout_time; for(c = 0; c < text.length; c++) { glo[glo.length] = {text:text, c:c, textScroller:textScroller}; timeout_time = 1000 + c * 200; setTimeout("append(" + (glo.length - 1) +")", timeout_time); } } function append(i) { var obj = glo[i]; obj.textScroller.innerHTML += obj.text[obj.c]; obj = null; glo[i] = null; } window.onload = initText; |
使用上面的内容,您只有一个全局数组
注意:第二个代码示例并不是OP问题的最佳或最合适的解决方案,但可能会受益于其他setTimeOut相对问题,例如。当有人想要进行演示或性能测试时,需要在延迟后调用某些功能。这段代码的优点是可以使用for循环(许多编码器想要用于循环)以及使用内循环的可能性以及将其循环时间状态中的局部变量"发送"到timeOut函数的能力。
你的for循环是一次为每个字符设置一个超时,所以它们不会按顺序出现,而是一次性出现。你的setTimeout应该包含另一个setTimeout的代码,该setTimeout将包含要显示的下一个字符。
所以这样的事情(没有测试这个)
1 2 3 4 5 6 7 8 9 10 11 12 | function initText() { var textScroller = document.getElementById('textScroller'); var text = 'Hello how are you?'; setTimeout('nextChar(text)', 1000); } function nextChar(text){ if(text.length > 0){ textScroller.innerHTML += text[0]; setTimeout('nextChar(text.substring(1))', 1000); } } |