for 循环中的 setTimeout 更改最终输出;如何在不改变最终结果的情况下延迟 for 循环的运行

setTimeout in a for loop changes final output; how to delay runs of a for loop, without changing final result

我正在尝试使用 javascript 函数在我的网站上制作自定义打字机效果。为了在每个字母的输入之间添加延迟,我为 for 循环的每个 运行 实现了交错的 setTimeout,因此每次迭代与前一次相比额外延迟了 300 毫秒.我需要将特殊字符(' ' '<'、'>')输入为单个字符而不是单个字母,因此我有几个 else if 条件。当 setTimeout 被排除时,这会产生预期的效果。但是,添加延迟会导致在打印出整个字符后拼出此代码的各个字母。我该如何解决这个问题?

function type(fullTxt, current = '') {
    for (let i = current.length, j = 0; i < fullTxt.length; i++, j++) {
         setTimeout(function() {
            if (fullTxt.substring(i, i+6) === '&nbsp;') {
                console.log(fullTxt.substring(0, i+6));
                i = i + 5;
            } else if (fullTxt.substring(i, i+4) === '&lt;') {
                console.log(fullTxt.substring(0, i+4));
                i = i + 3;
            } else if (fullTxt.substring(i, i+3) === '&gt') {
                console.log(fullTxt.substring(0, i+3));
                i = i + 2;
            } else {
                console.log(fullTxt.substring(0, i+1));
            }
            console.log(j); //included just to ensure j is counting properly
            console.log(i); //included to check progress of loop
            console.log(fullTxt.length); //included to check endpoint of for loop
         }, j * 300);
    }
}

type('hello&nbsp;');

预期输出:

// h
// 0
// 0
// 11
// he
// 1
// 1
// 11
// hel
// 2
// 2
// 11
// hell
// 3
// 3
// 11
// hello
// 4
// 4
// 11
// hello&nbsp;
// 5
// 10
// 11

您可以将 setTimeout 仅放在 console.log 上,而不是围绕整个 if 语句。

function type(fullTxt, current = '') {
  for (let i = current.length, j = 0; i < fullTxt.length; i++, j++) {
    if (fullTxt.substring(i, i + 6) === '&nbsp;') {
      setTimeout(function() {
        console.log(fullTxt.substring(0, i + 6));
      }, j * 300);
      i = i + 5;
    } else if (fullTxt.substring(i, i + 4) === '&lt;') {
      setTimeout(function() {
        console.log(fullTxt.substring(0, i + 4));
      }, j * 300);
      i = i + 3;
    } else if (fullTxt.substring(i, i + 3) === '&gt') {
      setTimeout(function() {
        console.log(fullTxt.substring(0, i + 3));
      }, j * 300);
      i = i + 2;
    } else {
      setTimeout(function() {
        console.log(fullTxt.substring(0, i + 1));
      }, j * 300);
    }
    setTimeout(function() {
      console.log(j); //included just to ensure j is counting properly
      console.log(i); //included to check progress of loop
      console.log(fullTxt.length); //included to check endpoint of for loop
    }, j * 300);
  }
}

type('hello&nbsp;');

您可以使用 async 函数实现此目的

 async function type(fullTxt, current = '') {
        for (let i = current.length, j = 0; i < fullTxt.length; i++, j++) {
             await waitFor(j*300);
                if (fullTxt.substring(i, i+6) === '&nbsp;') {
                    console.log(fullTxt.substring(0, i+6));
                    i = i + 5;
                } else if (fullTxt.substring(i, i+4) === '&lt;') {
                    console.log(fullTxt.substring(0, i+4));
                    i = i + 3;
                } else if (fullTxt.substring(i, i+3) === '&gt') {
                    console.log(fullTxt.substring(0, i+3));
                    i = i + 2;
                } else {
                    console.log(fullTxt.substring(0, i+1));
                }
                console.log(j); //included just to ensure j is counting properly
                console.log(i); //included to check progress of loop
                console.log(fullTxt.length); //included to check endpoint of for loop
             }
        }
    


type('hello&nbsp;');

这里是waitFor函数

function waitFor(ms){
  return new Promise(resolve=> setTimeout(resolve,ms))
}

现在更安全的是使用async/await,调用一个Promise,这样,你的循环实际上是在等待前一个循环完成。

这也使得内容易于编写或稍后修改。

演示的超时设置为 2000 毫秒。

async function type(fullTxt, current = '') {
    for (let i = current.length, j = 0; i < fullTxt.length; i++, j++) {
            await wait(2000) // Wait for 2000ms
            if (fullTxt.substring(i, i+6) === '&nbsp;') {
                console.log(fullTxt.substring(0, i+6));
                i = i + 5;
            } else if (fullTxt.substring(i, i+4) === '&lt;') {
                console.log(fullTxt.substring(0, i+4));
                i = i + 3;
            } else if (fullTxt.substring(i, i+3) === '&gt') {
                console.log(fullTxt.substring(0, i+3));
                i = i + 2;
            } else {
                console.log(fullTxt.substring(0, i+1));
            }
            console.log(j); //included just to ensure j is counting properly
            console.log(i); //included to check progress of loop
            console.log(fullTxt.length); //included to check endpoint of for loop       
    }
}

// Generic Promise function
function wait(delayInMS) {
  return new Promise((resolve) => setTimeout(resolve, delayInMS));
}

type('hello&nbsp;');