Javascript 如何等待使用setTimeout递归调用自身的函数完成?

Javascript 如何等待使用setTimeout递归调用自身的函数完成?,javascript,asynchronous,animation,recursion,Javascript,Asynchronous,Animation,Recursion,我是Javascript新手,目前正在开发一个网站,随着时间的推移,它会改变自己的外观 这一页的一部分是“打字机”,它一个字母一个字母地写出文本。 这是这台打字机的代码: function typeWriter(element, txt) { if (txt.length > 1) { element.textContent += txt.charAt(0); var newText = txt.slice(1,txt.length);

我是Javascript新手,目前正在开发一个网站,随着时间的推移,它会改变自己的外观

这一页的一部分是“打字机”,它一个字母一个字母地写出文本。 这是这台打字机的代码:

function typeWriter(element, txt) {
    if (txt.length > 1) {
        element.textContent += txt.charAt(0);
        var newText = txt.slice(1,txt.length);
        setTimeout(typeWriter, 150 , element, newText);
    } else {
        element.textContent += txt.charAt(0);
    }
}
现在,我想等待打字机函数完成其文本,然后再对我的背景色进行另一次更改

function runThis(){
    var line1 = document.getElementById("line1");
    typeWriter(line1, "This should be written first, before continuing");
    document.body.style.backgroundColor = "blue";
}
据我所知,setTimeout使我的打字机异步,因此,如果我像上面的例子那样做,第三行代码将在打字机到达第一个setTimeout时立即运行

我试图通过异步/等待条款和承诺来实现这一点。但即使在我做出承诺之后,我的“runThis”功能也不会在打字机完成后继续

function typeWriter(element, txt) {
    return new Promise (function(resolve,reject) {
        if (txt.length > 1) {
            element.textContent += txt.charAt(0);
            var newText = txt.slice(1,txt.length);
            setTimeout(typeWriter, 150, element, newText);
        } else {
            element.textContent += txt.charAt(0);
            resolve();
        }
    })
}


async function runThis() {
    var line1 = document.getElementById("line1");
    await typeWriter(line1, "papupa");
    console.log("waiting over")
    document.body.style.backgroundColor = "blue";
}
你能帮我找出这里出了什么问题吗?
非常感谢

您可以将函数作为另一个参数传递到最后运行

function typeWriter(element, txt, callback) {
    if (txt.length > 1) {
        element.textContent += txt.charAt(0);
        var newText = txt.slice(1,txt.length);
        setTimeout(typeWriter, 150 , element, newText, cb);
    } else {
        element.textContent += txt.charAt(0);
        callback();
    }
}

typeWriter(el, "ABCDEF", runthis);

您可以将函数作为另一个参数传递到最后运行

function typeWriter(element, txt, callback) {
    if (txt.length > 1) {
        element.textContent += txt.charAt(0);
        var newText = txt.slice(1,txt.length);
        setTimeout(typeWriter, 150 , element, newText, cb);
    } else {
        element.textContent += txt.charAt(0);
        callback();
    }
}

typeWriter(el, "ABCDEF", runthis);

您创建了多个承诺,并且只解决了最后一个。 您可以将递归函数定义为内部函数,下面是一个示例:

function typeWriter(element, text) {
    return new Promise (function(resolve,reject) {
        function recursion(txt) {
            element.textContent += txt.charAt(0);
            if (txt.length > 1) {
                var newText = txt.slice(1, txt.length);
                setTimeout(recursion, 150, newText);
            } else {
                resolve();
            }
        }
        recursion(text);
    });
}

您创建了多个承诺,并且只解决了最后一个。 您可以将递归函数定义为内部函数,下面是一个示例:

function typeWriter(element, text) {
    return new Promise (function(resolve,reject) {
        function recursion(txt) {
            element.textContent += txt.charAt(0);
            if (txt.length > 1) {
                var newText = txt.slice(1, txt.length);
                setTimeout(recursion, 150, newText);
            } else {
                resolve();
            }
        }
        recursion(text);
    });
}

您可以将
setTimeout
包装在承诺中。这将允许您使用
async/await
语法更清楚地表达代码的意图,就像它是同步运行的一样


异步函数runThis(){
var line1=document.getElementById(“line1”);
等待打字机(第1行,“papupa”);
document.body.style.backgroundColor=“蓝色”;
}
异步功能打字机(元素,txt){
对于(变量i=0;i
您可以将
设置超时
包装在承诺中。这将允许您使用
async/await
语法更清楚地表达代码的意图,就像它是同步运行的一样


异步函数runThis(){
var line1=document.getElementById(“line1”);
等待打字机(第1行,“papupa”);
document.body.style.backgroundColor=“蓝色”;
}
异步功能打字机(元素,txt){
对于(变量i=0;i
这是因为第一次调用
打字机
返回的承诺从未得到解决,您只是在解决创建的最后一个承诺。感谢您解释我的错误所在!这是因为第一次调用
打字机
返回的承诺从未得到解决,您只是在解决创建的最后一个承诺。感谢您解释我的错误所在!所以,如果我写多行,中间有不同的变化,我每次运行打字机时都需要一个不同的“runthis”,对吗?是的。您可以使用一个接受参数的函数,并使用匿名函数通过特定参数调用它,
typeWriter(el,“ACBDEF”,()=>runthis(“x”)typeWriter(el,“ACBDEF”,()=>runthis(“x”)我是否也可以在else部分中返回“resolve();”并将“returnnewpromise”部分移动到我的“runThis()”函数中?可能const typeWriterPromise=newpromise(函数(解析,拒绝){typeWriter(元素,文本);}?然后承诺将在打字机外解析?@PIcreamsoda我不确定我是否正确理解您的要求,但递归函数需要访问
resolve
。这就是为什么我在承诺中定义它,其中
resolve
在范围内。我是否也可以返回“resolve();”在else部分中,将“returnnewpromise”部分移动到我的“runThis()”函数中?可能const typeWriterPromise=newpromise(函数(解析,拒绝){typeWriter(元素,文本);}?然后承诺将在打字机之外得到解决?@PIcreamsoda我不确定我是否正确理解了您的要求,但递归函数需要访问
resolve
。这就是为什么我在承诺中定义它,其中
resolve
在范围内。我想我最喜欢这个解决方案。它非常简单理解。在使用此解决方案时,在最佳实践方面有什么我应该注意的吗?我认为我最喜欢此解决方案。理解此解决方案非常简单。在使用此解决方案时,在最佳实践方面有什么我应该注意的吗?