setTimeout里面的for循环

时间:2009-11-21 20:33:19

标签: javascript loops settimeout

我想要一个字符串,使用以下代码显示字符:

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;

它不起作用..我做错了什么?

9 个答案:

答案 0 :(得分:35)

尝试这样的事情:

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);

}

注意我添加了clearInterval以在需要时停止它。

答案 1 :(得分:4)

目前,您正在定义18个超时,所有将立即执行。 第二个问题是,您将指令作为String传递。在这种情况下,代码将无法访问initText中定义的所有变量,因为已评估的代码将在全局范围内执行。

IMO,这应该做的工作

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);
        }
    })();
}

答案 2 :(得分:3)

@ yauhen-yakimovich比answer更通用:

使用Timeout

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
    };
})();

使用Interval

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
    };
})();

注释中指示的两者之间略有差异 - repeat方法仅在回调执行后重复,因此如果您有“慢”回调,它将不会每delay ms运行一次,但执行后每delay重复,而loop方法将每隔delay ms触发一次回调。要提前停止,repeat会使用对象作为返回的标识符,因此请改用clearTimeout(timer.t)

用法:

就像@ soufiane-hassou的answer一样:

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);

如前所述,过早停车将是:

/* if repeat */ clearTimeout(interval.t);
/* if loop */   clearInterval(interval);

答案 3 :(得分:2)

试试这个:

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;

答案 4 :(得分:1)

尝试使用闭包:

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(它在您的函数中定义)。

答案 5 :(得分:1)

我想分享一个片段(根据Soufiane Hassou的回答)。它延伸到这样一种情况,即你在一个固定的时间间隔内替换一个for循环体来迭代某个数组。基本相同的同步循环,但“睡眠”暂停(因为javascript不是同步编程语言)。

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);
}

用法示例:

loop([1, 2, 3, 4], function(index, elem){
    console.log('arr[' + index + ']: ' + elem);
});

在Node JS中测试过。希望有所帮助。

<强>编辑&gt;

以下更新使代码可以与libs一起使用繁重的“原型设计”(如jQuery或原型):

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);
}

答案 6 :(得分:0)

你的for循环正在为每个字符设置一次超时,因此它们不会按顺序出现,而是一次性出现。你的setTimeout应该包含另一个setTimeout的代码,该setTimeout将包含要显示的下一个字符。

这样的事情(没有测试过这个)

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);
    }
}

答案 7 :(得分:0)

如果你想保留setTimeOut(而不是setInterval)并使用命名函数(而不是在setTimeOut调用中评估代码块),那么这可能会有所帮助:

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;

通过上述内容,您可以将参数传递给追加函数。

要传递几个参数,下一个代码可以解决问题:

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;

通过上述内容,您只有一个全局数组glo。在循环中,您创建新的数组成员到glo,在append()函数中使用索引来引用这些成员,该索引作为参数传递。

注意:第二个代码示例并不是OP问题的最佳或最合适的解决方案,但可能会受益于其他setTimeOut相对问题,例如。当有人想要进行演示或性能测试时,需要在延迟后调用某些功能。这段代码的优点是可以使用for循环(许多编码器想要用于循环)以及使用内部循环的可能性以及将循环时间状态中的局部变量“发送”到timeOut函数的能力。

答案 8 :(得分:0)

可能更好地循环级联。例如,淡化div:

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);
}