javascript随时间延迟而

发布于 2025-01-29 06:27:20 字数 2025 浏览 3 评论 0原文

我的目标我想在n MS(例如:200ms)时间间隔中逐步降低全局变量的循环。

提前致谢!

我已经尝试过的是

我尝试使用acy等待的东西。但是与CSS过渡结合使用,我在无限的环路中运行(in Codepen.io)。但是在这里,您会发现,如果您不断按下箭头,它就会开始顺利运行。

const procentage = document.querySelector(".procentage");
const green = engine.querySelector(".green");
let number = 0;
let decrementing  = false;

window.addEventListener('keydown', (e) => {
  e = e || window.event;
  e.preventDefault();
  
  if (e.keyCode == '38') {
    console.log("accelerate");     
    actionHandler( number++ );
    decrementing = false;
    downLoop();
  }
});


function actionHandler(num) {
  procentage.innerHTML = num;
  const str = num + "%"
  green.style.width = str;
  procentage.innerHTML = str;    
}

window.addEventListener('keyup', (e) => {
  e = e || window.event;
  e.preventDefault();
  
  if (e.keyCode == '38') {
    console.log("decelerate");
    decrementing = true;
    downLoop();
  }
});


async function downLoop() {
  if (! decrementing) {
    return false
  };
  
  const timer = ms => new Promise(res => setTimeout(res, ms));
   
  while (number > 1) {
    // how to decrement ever 200ms???
    actionHandler( number-- );      
    await timer(200)
  }

}
#engine {
  background-color:black;
  height: 50px;
  position: relative;
}

p {
  text-align: center;
}

.green {
  background:green;
  height: 50px;
  width:0%;
  transition: width 0.2s;
  text-align:center;
}
.procentage {
  position:absolute;
  top: 50%;
  left: 50%;
  transform: translate(0%,-50%);
  color: white;
  fon-weight: bold;
  font-size:28px;
}
<div id="engine">
  <div><span class="procentage">0</span></div>
  <div class="green"></div>    
</div>
<p>press arrow Up</p>

My goal I want to run loop that decrements a global variable stepwise in n ms (for Example: 200ms) time intervals.

Thanks in advance!

What i already tried

I tried to use ascy await. But in combination with css transition i run in an infinite loop (In codepen.io). But here in SO you will see that it starts not running smoothly if you keep pressing arrow up.

const procentage = document.querySelector(".procentage");
const green = engine.querySelector(".green");
let number = 0;
let decrementing  = false;

window.addEventListener('keydown', (e) => {
  e = e || window.event;
  e.preventDefault();
  
  if (e.keyCode == '38') {
    console.log("accelerate");     
    actionHandler( number++ );
    decrementing = false;
    downLoop();
  }
});


function actionHandler(num) {
  procentage.innerHTML = num;
  const str = num + "%"
  green.style.width = str;
  procentage.innerHTML = str;    
}

window.addEventListener('keyup', (e) => {
  e = e || window.event;
  e.preventDefault();
  
  if (e.keyCode == '38') {
    console.log("decelerate");
    decrementing = true;
    downLoop();
  }
});


async function downLoop() {
  if (! decrementing) {
    return false
  };
  
  const timer = ms => new Promise(res => setTimeout(res, ms));
   
  while (number > 1) {
    // how to decrement ever 200ms???
    actionHandler( number-- );      
    await timer(200)
  }

}
#engine {
  background-color:black;
  height: 50px;
  position: relative;
}

p {
  text-align: center;
}

.green {
  background:green;
  height: 50px;
  width:0%;
  transition: width 0.2s;
  text-align:center;
}
.procentage {
  position:absolute;
  top: 50%;
  left: 50%;
  transform: translate(0%,-50%);
  color: white;
  fon-weight: bold;
  font-size:28px;
}
<div id="engine">
  <div><span class="procentage">0</span></div>
  <div class="green"></div>    
</div>
<p>press arrow Up</p>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

淡看悲欢离合 2025-02-05 06:27:20

每当动画时,您都不应依靠setIntervalsettimeout,因为这意味着您将更新“ x milliseconds之后的某个地方”,这通常会在屏幕重新粉刷,因此会导致Janky动画。

相反,您应使用 requestAnimationFrame 在每次重新粉刷之前。因此,如果您的帧率为60 Hz,则意味着您每秒将进行60次重新涂漆。对于每次重新粉刷,请检查自上次更新以来是否已经过去了(syredtriggerupdate()下面),然后检查是否应该更新数字。

我还添加了类keyhandler,以跟踪按下哪些键。

最后我变得草率了,只是添加了一个if语句的“ else”。当您想设置更多按下按键时,您会弄清楚一些东西。

您不应使用 keyboardEvent.keycode.keycode ,但是而是keyboardEvent.code

const procentage = document.querySelector(".procentage");
const green = engine.querySelector(".green");
let number = 0;
let speed = 200      // ms
let lastUpdated = 0; // ms
let animationId = 0; // use later on to pause the animation

class KeyHandler {
  ArrowLeft  = false
  ArrowUp    = false
  ArrowRight = false
  ArrowDown  = false

  #setKey(code, value) { // private method
    if (typeof this[code] != undefined) {
      this[code] = value;
    }
  }

  set pressedKey(code) {
    this.#setKey(code, true);
  }

  set releasedKey(code) {
    this.#setKey(code, false);
  }
}

let keyHandler = new KeyHandler();

window.addEventListener('keydown', (e) => {
  e = e || window.event;
  e.preventDefault();
  keyHandler.pressedKey = e.code;
});

window.addEventListener('keyup', (e) => {
  e.preventDefault();
  keyHandler.releasedKey = e.code
});


function actionHandler(num) {
  const str = num + "%"
  green.style.width = str;
  procentage.innerHTML = str;
}

function shouldTriggerUpdate(timeInMillis) {
  let difference = timeInMillis - lastUpdated;

  return difference >= speed;
}

function planeAnimation() {
  let timeInMillis = new Date().getTime();
  
  if (shouldTriggerUpdate(timeInMillis)) {
    lastUpdated = timeInMillis;
    
    if (keyHandler.ArrowUp) {
      actionHandler(++number)
    } else if (number > 0) {
      actionHandler(--number)
    }
  }

  animationId = requestAnimationFrame(planeAnimation)
}

animationId = requestAnimationFrame(planeAnimation);
#engine {
  background-color: black;
  height: 50px;
  position: relative;
}

p {
  text-align: center;
}

.green {
  background: green;
  height: 50px;
  width: 0%;
  transition: width 0.2s;
  text-align: center;
}

.procentage {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(0%, -50%);
  color: white;
  fon-weight: bold;
  font-size: 28px;
}
<div id="engine">
  <div><span class="procentage">0</span></div>
  <div class="green"></div>
</div>
<p>press arrow up</p>

Whenever you animate, you shouldn't rely on setInterval or setTimeout, because that means that you will update "somewhere after X milliseconds" which will often end up in the middle of a screen repaint, and will therefor cause janky animation.

Instead, you should use RequestAnimationFrame which does a calculation before every repaint. So if you got a monitor with a framerate of 60 Hz, that means that you will do 60 repaints every second. For each repaint, check if enough time have passed since the last update (shouldTriggerUpdate() below) and then check if you should update the number.

I also added the class KeyHandler to keep track of which keys that have been pressed.

I got sloppy at the end and just added a decrement as an "else" of the if statement. You will figure something out when you get there when you want to set up more keys to be pressed.

You shouldn't use KeyboardEvent.keyCode, but instead KeyboardEvent.code.

const procentage = document.querySelector(".procentage");
const green = engine.querySelector(".green");
let number = 0;
let speed = 200      // ms
let lastUpdated = 0; // ms
let animationId = 0; // use later on to pause the animation

class KeyHandler {
  ArrowLeft  = false
  ArrowUp    = false
  ArrowRight = false
  ArrowDown  = false

  #setKey(code, value) { // private method
    if (typeof this[code] != undefined) {
      this[code] = value;
    }
  }

  set pressedKey(code) {
    this.#setKey(code, true);
  }

  set releasedKey(code) {
    this.#setKey(code, false);
  }
}

let keyHandler = new KeyHandler();

window.addEventListener('keydown', (e) => {
  e = e || window.event;
  e.preventDefault();
  keyHandler.pressedKey = e.code;
});

window.addEventListener('keyup', (e) => {
  e.preventDefault();
  keyHandler.releasedKey = e.code
});


function actionHandler(num) {
  const str = num + "%"
  green.style.width = str;
  procentage.innerHTML = str;
}

function shouldTriggerUpdate(timeInMillis) {
  let difference = timeInMillis - lastUpdated;

  return difference >= speed;
}

function planeAnimation() {
  let timeInMillis = new Date().getTime();
  
  if (shouldTriggerUpdate(timeInMillis)) {
    lastUpdated = timeInMillis;
    
    if (keyHandler.ArrowUp) {
      actionHandler(++number)
    } else if (number > 0) {
      actionHandler(--number)
    }
  }

  animationId = requestAnimationFrame(planeAnimation)
}

animationId = requestAnimationFrame(planeAnimation);
#engine {
  background-color: black;
  height: 50px;
  position: relative;
}

p {
  text-align: center;
}

.green {
  background: green;
  height: 50px;
  width: 0%;
  transition: width 0.2s;
  text-align: center;
}

.procentage {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(0%, -50%);
  color: white;
  fon-weight: bold;
  font-size: 28px;
}
<div id="engine">
  <div><span class="procentage">0</span></div>
  <div class="green"></div>
</div>
<p>press arrow up</p>

浅语花开 2025-02-05 06:27:20

从上面的评论...

“而不是每次号码值按下新的async计时器函数,设置为200 msec延迟,但不会立即触发,而是将其触发到数组中。创建通过 语句可以再次减少号码。” - Peter Seliger

“@peterseliger嗨,彼得!谢谢你的评论。你能做一个小例子吗?” - Maik Lowrey

和这里要求的演示。

function createWait(delay) {
  return async function wait () {
    let settle;
    const promise = new Promise((resolve) => { settle = resolve;});
    setTimeout(settle, delay, { delay, state: 'ok' });
    return promise;
  };
}
async function* getWaitIterables(list) {
  let wait;
  while (wait = list.shift()) {

    yield wait();
  }
}

// demo for ...
// - creating an async `wait` function
//   or a list of such kind.
// - creating an async generator from
//   a list of async `wait` functions.
// - iterating an async generator of
//   async `wait` functions.

const waitingList = [ //  const waitingList = [];
  2000,               //  waitingList.push(createWait(2000));
  1000,               //  waitingList.push(createWait(1000));
  3000,               //  waitingList.push(createWait(3000));
].map(createWait);    //  - The OP of cause needs to push into.

let number = 3;       //  - The incremented `number` value e.g. ... 3.

(async () => {
  for await (const { delay, state } of getWaitIterables(waitingList)) {
    --number;
    console.log({ number, delay, state });
  }
})();

console.log('... running ...', { number });
.as-console-wrapper { min-height: 100%!important; top: 0; }

From the above comments ...

"Instead of incrementing each time the number value push a new async timer function, set to 200 msec delay but not immediately triggered, into an array. Create an async generator from it and iterate over the latter via the for-await...of statement where one could decrement number again." – Peter Seliger

"@PeterSeliger Hi Peter! Thank you for your comment. Can you make a small example please?" – Maik Lowrey

And here the requested demonstration.

function createWait(delay) {
  return async function wait () {
    let settle;
    const promise = new Promise((resolve) => { settle = resolve;});
    setTimeout(settle, delay, { delay, state: 'ok' });
    return promise;
  };
}
async function* getWaitIterables(list) {
  let wait;
  while (wait = list.shift()) {

    yield wait();
  }
}

// demo for ...
// - creating an async `wait` function
//   or a list of such kind.
// - creating an async generator from
//   a list of async `wait` functions.
// - iterating an async generator of
//   async `wait` functions.

const waitingList = [ //  const waitingList = [];
  2000,               //  waitingList.push(createWait(2000));
  1000,               //  waitingList.push(createWait(1000));
  3000,               //  waitingList.push(createWait(3000));
].map(createWait);    //  - The OP of cause needs to push into.

let number = 3;       //  - The incremented `number` value e.g. ... 3.

(async () => {
  for await (const { delay, state } of getWaitIterables(waitingList)) {
    --number;
    console.log({ number, delay, state });
  }
})();

console.log('... running ...', { number });
.as-console-wrapper { min-height: 100%!important; top: 0; }

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文