0

I am using this snippet of code

let submitBtn,
    stopBtn,
    firstStepInput,
    lastStepInput,
    output = 0,
    stopOutput = 0;


document.addEventListener("DOMContentLoaded", () => {
    submitBtn = document.querySelector('#submit');
    stopBtn = document.querySelector('#stop');
    firstStepInput = document.querySelector('#firstStep');
    lastStepInput = document.querySelector('#lastStep');
    output = document.querySelector('#output');
    stopOutput = document.querySelector('#stopOutput');

    submitBtn.addEventListener('click', getValueInputs);
    stopBtn.addEventListener('click', getValueStopOutput);
})

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

const getValueInputs = () => {
    let firstInputValoue = +firstStepInput.value || 0;
    let lastInputValoue = +lastStepInput.value || 100;

    for (let i = firstInputValoue; i <= lastInputValoue; i++) {
        sleep(i * 1000).then(_ => {
            output.innerHTML = i;
        })
    }
}

const getValueStopOutput = () => {
    stopOutput.innerHTML = output.innerHTML;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"/>
 <div>

        <div class="ms-3">
            <div class="d-flex align-items-center mt-3">
                <div>
                    <label for="firstStep">firstStep</label>
                    <input id="firstStep" type="number" class="form-control" />
                </div>
                <span class="mx-3">to</span>
                <div>
                    <label for="lastStep">lastStep</label>
                    <input id="lastStep" type="number" class="form-control" />
                </div>
            </div>
            <div class="mt-3 mx-auto">
                <button id="submit" class="btn btn-sm btn-primary">Submit</button>
                <button id="stop" class="btn btn-sm btn-info">Stop</button>
            </div>
            <div class="mt-3">
                <p id="output"></p>
            </div>
            <div class="mt-3">
                <p id="stopOutput"></p>
            </div>
        </div>

    </div>

And with the help of this link, I was able to make a sleep function And it works perfectly

Now I have a problem that I can't stop and disable!

Now, for example, we put the number 0 in the input firstStep And in input lastStep for example 100 or more In this case, it takes 100 seconds for this function to finish Now my question is, in the meantime, if the user wants to stop the function altogether or enter new numbers, what should I do?

davood beheshti
  • 213
  • 1
  • 11
  • 3
    This is a poor solution. Why are you not just using `setTimeout` or `setInterval` – Tangentially Perpendicular Mar 04 '23 at 20:29
  • 4
    Can you be specific how you would like it to work? What would be the trigger to interrupt "in the middle"? What do you want to give new values? The `sleep` function which you interrupted? Then do you really want to *prolong* a delay so it is longer than initially planned? – trincot Mar 04 '23 at 20:31
  • 2
    You seemed to have arrived at a solution to your problem and are now dead set on making it work. You’d get better mileage if you asked how to solve your actual problem, instead of the problem you encountered while trying to implement this sleep thing – Adam Jenkins Mar 05 '23 at 00:13
  • Hello good time @trincot I apologize for the delay in replying to you In fact, I receive two inputs from the user, for example, to go from the number x to the number y in a specific time Now there is a possibility that the user will ignore the number he gives and give new numbers, and I don't know how to cancel the previous function and start new numbers? – davood beheshti Mar 06 '23 at 18:24
  • Hello, good time @Adam, I apologize for the delay in replying and unfortunately my problem has not been solved yet Actually, this piece of code is the main part of my project, where I want to make something like a timer that traverses a path of two numbers it receives from user input. And at the same time, I can receive new entries from the user and stop the previous one. Now, as long as I don't receive new entries from the user, this works correctly, as soon as I receive new entries, it crashes correctly and the numbers are printed on top of each other. – davood beheshti Mar 06 '23 at 18:35
  • 1
    Please add your code **inside** the question, not behind a link. You can create a runnable snippet in your question using a toolbar button and add the HTML, CSS and JS. – trincot Mar 06 '23 at 19:38
  • 1
    Set Timeout is callback function we are achieving sleep function like Java so i am using same type of syntax for it i think no any other option and technique can achieve this type of flow then how we can use set Interval in for loop to achieve sleep like functionality – Jerry Mar 06 '23 at 19:46
  • 1
    @davod Please add that info also to your question by [edit]ing it. Btw, when you say you receive only two inputs, does that mean the "specific time" is fixed? Or is that a third input besides the numbers x and y? Also how does the animation start, is there a "submit" button, does it update while the user is typing the numbers, or is the animation timeline fixed? Or something else? – Bergi Mar 06 '23 at 19:54
  • What you asked was done @trincot – davood beheshti Mar 06 '23 at 20:34
  • 1
    I have included an example of the project in the code, please see @Bergi Now, as you can see, if we fill the inputs twice with different numbers that are far apart, we can see that every time the submit button is clicked, a new function is executed and the previous function is not stopped. – davood beheshti Mar 06 '23 at 20:39
  • 1
    @davod what if user enters first step 100 and last step 1000 then what outcome should come? – Jerry Mar 06 '23 at 20:41
  • @AniketRaj It should go from 100 to 1000 so that each step takes 1 second And this is true The problem is that while this function is running 100 to 1000 If another number is entered, for example, 200 to 2000, the function should stop here, and the part 200 to 2000 should start, and the previous one, i.e. 100 to 1000, should be stopped, which does not happen. – davood beheshti Mar 06 '23 at 20:48

2 Answers2

1

You could use a global variable that uniquely identifies the current animation with a sequential integer.

Whenever the user clicks either button, you would increase that identifier. The loop that performs the animation should check whether the series identifier it started with is still unchanged, otherwise it should exit.

Here is your adapted code:

let submitBtn,
    stopBtn,
    firstStepInput,
    lastStepInput,
    output = 0,
    stopOutput = 0;


document.addEventListener("DOMContentLoaded", () => {
    submitBtn = document.querySelector('#submit');
    stopBtn = document.querySelector('#stop');
    firstStepInput = document.querySelector('#firstStep');
    lastStepInput = document.querySelector('#lastStep');
    output = document.querySelector('#output');
    stopOutput = document.querySelector('#stopOutput');

    submitBtn.addEventListener('click', getValueInputs);
    stopBtn.addEventListener('click', getValueStopOutput);
})

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

let lastSeries = 0; // Unique number that identifies the current animation 
const getValueInputs = async () => {
    let thisSeries = ++lastSeries;
    let firstInputValoue = +firstStepInput.value || 0;
    let lastInputValoue = +lastStepInput.value || 100;

    // Loop condition also checks the unique series identifier
    for (let i = firstInputValoue; i <= lastInputValoue && thisSeries == lastSeries; i++) {
        output.textContent = i;
        await sleep(1000);
    }
}

const getValueStopOutput = () => {
    stopOutput.textContent = output.innerHTML;
    ++lastSeries; // This will interrupt the animation.
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"/>
 <div>
    <div class="ms-3">
        <div class="d-flex align-items-center mt-3">
            <div>
                <label for="firstStep">firstStep</label>
                <input id="firstStep" type="number" class="form-control" />
            </div>
            <span class="mx-3">to</span>
            <div>
                <label for="lastStep">lastStep</label>
                <input id="lastStep" type="number" class="form-control" />
            </div>
        </div>
        <div class="mt-3 mx-auto">
            <button id="submit" class="btn btn-sm btn-primary">Submit</button>
            <button id="stop" class="btn btn-sm btn-info">Stop</button>
        </div>
        <div class="mt-3">
            <p id="output"></p>
        </div>
        <div class="mt-3">
            <p id="stopOutput"></p>
        </div>
    </div>

</div>
trincot
  • 317,000
  • 35
  • 244
  • 286
0

Here code help you to create the counter in term of start|stop|pause|resume

  1. start : counter starts what is in the input
  2. stop : counter stops and if you start or resume then it will start from start input value.
  3. pause : counter stops but states saved and when you resume it continues from last steps.
  4. resume: resume starts from saved state.

let running = false;
      let startCounter = 0;
      let endCounter = 0;
      let _id = (e) => document.getElementById(e);

      const [ssRef, esRef, startRef, stopRef, print, pause, resume] = [
        'ss',
        'es',
        'start',
        'stop',
        'print',
        'pause',
        'resume'
      ].map((e) => _id(e));

      function sleep(timer) {
        return new Promise((resolve) => {
          setTimeout(() => {
            resolve(running);
          }, timer);
        });
      }

      //
      async function stepsCounter() {
        for (startCounter; startCounter < endCounter; startCounter++) {
          const runningFlag = await sleep(500);
          if (!runningFlag) {
            return;
          }
          print.innerHTML = `${startCounter}`;
        }

        running = false;
      }

      startRef.addEventListener('click', () => {
        if (!ssRef.value || !esRef.value) {
          return alert('Enter valid enput');
        } else {
          startCounter = +ssRef.value;
          endCounter = +esRef.value;
          if (!running) {
            running = true;
            stepsCounter();
          }
        }
      });

      stopRef.addEventListener('click', () => {
        running = false;
        startCounter = +ssRef.value
      });

      pause.addEventListener('click', () => {
        running = false;
      });

      resume.addEventListener('click', () => {
        running = true;
        stepsCounter();
      });
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Home</title>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <!--
      Need a visual blank slate?
      Remove all code in `styles.css`!
    -->
    <link rel="stylesheet" href="styles.css" />
    <script type="module" src="script.js"></script>
  </head>
  <body>
    <div>
      start step: <input type="text" id="ss" />
      <br />
      end step: <input type="text" id="es" />

      <br />
      <button type="button" id="start">Start</button>
      <br />
      <button type="button" id="stop">Stop</button>
      <br />
      <button type="button" id="pause">Pause</button>
      <br>
      <button type="button" id="resume">Resume</button>
      <br>
      print: <span id="print"></span>
    </div>
  </body>
</html>
Jerry
  • 1,005
  • 2
  • 13