使用setTimeout在创建新元素之间强制延迟

Using setTimeout to force delays between creating new elements

本文关键字:之间 延迟 元素 setTimeout 创建 新元素 使用      更新时间:2023-10-11

我试图制作一个p,然后有一个延迟,然后制作另一个p。我的战斗函数可以工作,直到我尝试添加setTimeout。我试过在任何地方都使用setTimeout,但没有效果。有时它会创建一个无限循环,在某些地方,它可以在同时创建每个p之前进行延迟。

效果应该类似于点击攻击按钮

我试着使用与这个代码笔的创建者相同的方法,但我不明白他的代码是如何工作的。

这是演示

function timeout() {
  setTimeout(function() {
  }, 500);
}
var battle = function() {
  while (monsterHP > 0) {
    var playerDam = Math.floor(Math.random() * ((playerAtk - monsterAtk) + 2));
    var newP = $('#battle').append("<p>You have hit the monster for " + playerDam + " damage. The monster has " + (monsterHP - playerDam) + "HP left</p>");
    monsterHP -= playerDam;
    timeout();
    if (monsterHP <= 0) {
      $('#battle').append("<p>You have defeated the monster</p>");
    }
  }
}

$('#battleButton').click(function() {
  battle();
});

我试着在评论中解释,但它不适合,因为这里发生了一些事情。修复它并谈论新代码更容易:

var battle = function() {
  var i=0;
  while (monsterHP > 0) {
    (function(hp){
    var playerDam = Math.floor(Math.random() * ((playerAtk - monsterAtk) + 2));
    monsterHP-= playerDam;
   hp= monsterHP; // this might or might not be needed.
   setTimeout(function(){
    var newP = $('#battle').append("<p>You have hit the monster for " + playerDam + " damage. The monster has " + (hp - playerDam) + "HP left</p>");
    if (hp<= 0)$('#battle').append("<p>You have defeated the monster</p>");
   }, i++ * 500);

   }(monsterHP));
  }
}

在这里,我已经将计算移动到循环的顶部,然后将计算的可见操作推迟到setTimeout之后1/2秒。

您需要由循环更改的vars的私有副本,并且需要一个可以使用这些值的超时。

您可以稍微更改您的battle函数,而不是使用while循环,只需让setTimeout()调用为您循环即可。

以下是我修改你的链接小提琴的例子:

var playerAtk = 5;
var playerDef = 5;
var playerHP = 10;
var monsterAtk = 4;
var monsterDef = 4;
var monsterHP = 8;
var battle = function() {
  if (monsterHP > 0)
  {
    var playerDam = Math.floor(Math.random() * ((playerAtk - monsterAtk) + 2));
    var newP = $('#battle').append("<p>You have hit the monster for " + playerDam + " damage. The monster has " + (monsterHP - playerDam) + "HP left</p>");
    monsterHP -= playerDam;
    setTimeout(function() {
      battle();
    }, 1000);
  }
  else {
    $('#battle').append("<p>You have defeated the monster</p>");
  }
}

$('#battleButton').click(function() {
  battle();
});

你可以在这里看到我的JSFiddle

您遇到的问题是timeout的实现。正如tymeJV在评论中提到的,setTimeout是异步的。您的代码不会停止为完成超时而执行的操作。相反,您必须传递一个回调,以便在经过时间后完成(在您的情况下是附加元素)。

请在控制台中尝试此代码片段,以更好地说明这一点:

setTimeout(function() {
  console.log('hello from callback');
}, 3000)
console.log('hello from outside');

正如您所看到的,即使在超时之后,后面的代码也会首先运行。

接受的解决方案并行启动多个setTimeout()调用。在你的情况下,它往往只有不到12个并发定时器——尽管由于随机数的原因,无法保证它会启动多少个定时器。

在大多数情况下,最好每次暂停都从下一次开始,而不是像这样一次启动。例如,假设您需要报告一个运行时间比这长得多的进程的定期进度,或者一个一直运行到程序退出的进程?您将需要大量的并发超时。

这是一个代码版本,与原来的代码相比变化最小,并且在任何时候都只使用一个setTimeout(),以避免这个问题。

它的工作方式很简单:它根本不使用循环,而是battle()在需要再次运行时调用timeout()timeout()依次将battle作为参数传递给setTimeout(),因此当时间流逝时将调用battle()

我用//**为您标记了更改:

var playerAtk = 5;
var playerDef = 5;
var playerHP = 10;
var monsterAtk = 4;
var monsterDef = 4;
var monsterHP = 8;
function timeout() {
  //** Your original setTimeout call didn't do anything at all.
  //** setTimeout isn't a "delay and then return when the delay is done".
  //** Instead, it returns immediately, and the function you pass into it
  //** will be run after the time elapses.
  //** Here we pass battle, so that function is called after the timeout.
  setTimeout(battle, 500);
}
var battle = function() {
  //** This is now just an if instead of a while. It doesn't loop at all here.
  //** Instead, when we want to run another iteration, the setTimeout() call
  //** takes care of that by calling battle again.
  //** In fact, if monsterHP always starts positive, you don't need this
  //** if statement at all.
  if (monsterHP > 0) {
    var playerDam = Math.floor(Math.random() * ((playerAtk - monsterAtk) + 2));
    var newP = $('#battle').append("<p>You have hit the monster for " + playerDam + " damage. The monster has " + (monsterHP - playerDam) + "HP left</p>");
    monsterHP -= playerDam;
    if (monsterHP <= 0) {
      $('#battle').append("<p>You have defeated the monster</p>");
    } else {
      //** The final change: if monsterHP is still > 0, we call timeout()
      //** here to start the next battle call after the interval elapses.
      timeout();
    }
  }
}

$('#battleButton').click(function() {
  battle();
});

工作小提琴