【问题标题】:Javascript make functions execute one after anotherJavascript使函数一个接一个地执行
【发布时间】:2026-01-05 05:30:01
【问题描述】:

我已经设置了一些功能。 一个是打字效果,一个是段落效果,另一个是添加“ ”,一个是终端中的闪烁光标。所有这些都会改变 div 的 innerHTML。

当页面加载时,函数 Start() 内部有大约 10 个函数,它们组成了一系列应该发生的事情:文本写入、光标开始闪烁、段落、再次写入文本等。

问题是,它们都同时执行,除非我在 Start() 函数中对每个都使用 setTimeout()。这有点搞砸了,因为我必须为每个函数定义一个开始时间。

编辑:这里没有 JQuery。只是JavaScript。 这是我的整个 JS 文件:

ctrl = 0;
y=0;
block = 0;
test = "";
first_time = 1;

function typing(id, sentence){

        var index=0;
        var intObject= setInterval(function() {
               document.getElementById(id).innerHTML+=sentence[index]; 
               index++;
               if(index==sentence.length){
                     clearInterval(intObject);
                }
            }, 100);
}


function paragraph(x){
    while(x>0){
        document.getElementById("container").innerHTML+="<br>";
        x--;
    }
}

function advance(x){
    while(x>0){
        document.getElementById("container").innerHTML+="&nbsp;";
        x--;
    }
}


function blink(y){
    if(first_time == 1){ctrl = y; first_time=0;}
    if(ctrl!=0){
        if(block=='0'){
        test = document.getElementById("container").innerHTML;
            document.getElementById("container").innerHTML+="\u258B";
            block=1;
        }
        else if(block=='1'){
            document.getElementById("container").innerHTML=test;
            block=0;
        }
        ctrl--;
        setTimeout("blink(y);", 300);
    }
    if(ctrl==0){first_time=1;}
}


function start(){
    typing('container','Subject Name:');
    setTimeout("blink('4');",1700);
    setTimeout("typing('container',' Carlos Miguel Fernando');",2800);
    setTimeout("blink('6');",5600);
    setTimeout("paragraph('1');",7200);
    setTimeout("blink('8');",7400);
    setTimeout("typing('container','Age: 21');",9500);
    setTimeout("blink('4');",10800);
    setTimeout("paragraph('1');",12800);
    setTimeout("blink('4');",13200);
    setTimeout("typing('container','Location: Povoa de Varzim, Portugal');",14500);
    setTimeout("blink('14');",19000);
    setTimeout(function(){document.getElementById("more").style.display="block";}, 23000);
    setTimeout("typing('more','Find Out More');",24000);
}

【问题讨论】:

  • 除了将字符串传递给超时非常可怕之外,解决方案在很大程度上取决于您的函数。它们似乎是异步的,因此您必须使用回调或承诺。也许你需要一个动画队列。如果你不介意,你可以看看 jQuery,你已经实现了所有这些机制。
  • 问题比看起来更复杂。我建议你学习 JavaScript 中的回调和异步编程。寻找这些术语:“高阶函数”、“承诺”、“延续”。这应该让你开始。
  • 刚刚编辑并添加了我的整个 javascript 文件。也许这有点用处。我会得到一些关于异步函数和回调的信息,谢谢!

标签: javascript html function settimeout


【解决方案1】:

检查下面的代码

function blink(id)
{
    //Do something
    alert(id);

    if(id == 2)
    {
        //call typing with text
        blink(4);
    }
    if(id == 4)
    {
        //call typing with text
        blink(6);
    }
    if(id == 6)
    {
        //call typing with text
        blink(8);
    }
    if(id == 8)
    {
        //Complete
    }
}

然后调用blink(2);它会一个接一个地调用blink函数。

【讨论】:

  • 问题在于“使用文本调用输入”是异步的——它会立即返回,但活动仍在继续。如果blink 只是立即调用自己,那么所有步骤都将毫无延迟地运行。这与 OP 的原始非工作代码没有什么不同,他们只是按顺序调用函数。
【解决方案2】:

首先,您需要一种方法来找出函数何时结束。理想的机制称为承诺。 jQuery中有一个很好的实现。假设在您的活动列表中您想要人为延迟:

blink(4);
sleep(1000);   // wait 1 second
blink(4);

像这样实现:

var sleep = function(ms) {
    var result = $.Deferred();
    setTimeout(result.resolve, ms);
    return result.promise();
};

即创建一个$.Deferred,并返回它的promise(),但在这两者之间,启动一些稍后会完成的活动。当它发生时,调用resolve()(这里我只是让setTimeout直接调用它)。您可以将值传递给 resolve 作为函数的逻辑“返回值”。您也可以改为调用reject,这在逻辑上类似于抛出异常。

一旦你有一组返回承诺的构建块函数,你就可以这样做:

typing('container','Subject Name:').then(function() {
   return blink('4');
}).then(function() {
   return typing('container',' Test');
}).then(function() {
   return blink('4');
}).then(function() {
   // and so on
});

更新:

Click here to see a quick mock-up in jsbin.

【讨论】:

  • +1 因为 .. 承诺需要更多曝光。 (但是,应该注意,jQuery 1.8+ 可能应该用于正确的then 支持.. 或者这可能是另一个违背承诺的问题。还有Q 等等。)
  • 注意。我相信 Q 和 jQuery 的不同之处在于如果 resolve 在同一个承诺上被第二次调用(Q 抛出,jQuery 忽略)会发生什么。
  • 得到一个“Uncaught TypeError: Cannot call method 'then' of undefined”错误,一旦我让它工作,它仍然可以解决我的问题。谢谢!
  • @DanielEarwicker 有趣的知识点——我自己(还)从未遇到过这种情况。
  • @CarlosMiguelFernando - 听起来您需要在 SO 上提出新问题(或查找现有问题),例如“如何从我的 HTML/JavaScript 应用程序中引用 jQuery?”
最近更新 更多