0

I'm working on a Pomodoro-esque timer. The timer must be able to do the following:

When 'Start' button is pressed:

  • Start 5 second timer. Times will change, of course)
  • After timer expires, send AJAX event with start and end timestamp
  • Start a 3 second timer.
  • After timer expires, start a new 5 second timer. (Loop step 1 to 3 a total of FOUR times)
  • At the end of the fourth loop, start a 7 second timer.
  • After the 7 second timer expires, start the 5-3 loop again.

When 'Stop' button is pressed:

  • Cancel the timer, reset it back to the default state.

This is the code I have now:

HTML

<html>
<head>
    <meta charset="UTF-8">
    <title>Pomodoro Test</title>
    <link rel="stylesheet" type="text/css" href="main.css">
</head>
<body>
<div id="test"></div>
<div id="timer">5</div>

<button id="start">Start</button>
<button id="reset">Reset</button>

<div id="startTime"></div>
<div id="endTime"></div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
<script src="functions.js"></script>
</body>
</html>

JavaScript:

var timer = 5;
var flag = 0;
var startTime;
var endTime;
var intervalTimer;

function update() {
  if (timer-- > 0) {
    $("#timer").html(timer); // retrieve value from html
  } else {
    endTime = new Date();
    //alert("Start Time = " + startTime + "\nEnd Time = " + endTime);
    $("#endTime").html("End time: " + endTime.toTimeString());
    resetTimer();


    // TODO: send ajax call to server, sending startTime and endTime
    // so that these can be saved to database

  }
}
function loopingTimer() {
  while(flag === 0) {
    startTime = new Date();
    $("#startTime").html("Start time: " + startTime.toTimeString());
    startTimer();
    i++;
  setTimeout(function() {
    if(i < 5) {
      loopingTimer();
    }
  }, 3001)}};

$("#start").click(function() {
  loopingTimer();
});

$("#reset").click(function() {
    flag = 1;
  });



function startTimer() {
  intervalTimer = window.setInterval(update, 500);
}

function resetTimer() {
  stopTimer();
  timer = 5;
  $("#timer").text(timer);
}

function stopTimer() {
  window.clearInterval(intervalTimer);
}

I find it extremely difficult to get the desired functionality, I've been tinkering with this code for 2 days. I sincerely hope you guys can help me out.

Cake.

Cake
  • 493
  • 7
  • 16

1 Answers1

0

The while loop, in the loopingTimer function, does (simplified):

while (userDidntStop) {
    startTimer();
}

The break condition is that the user clicks on a button. If the user does so after 500 loopings (a very very very short time), then this loop will have created about 500 timers. The biggest issue is here: avoid running timers (or intervals the same) within loops.

Another issue is that startTime is reset in the almost-infinite loop. You could merge loopingTimer with startTimer, as they do basically a single thing, which is starting the timer, and thus preventing

Also, you use the timer variable to check for the elapsed time. Browsers do not have the obligation to provide the specified delays (at least for setTimeout, according to the MDN documentation. I think it is also the case for setInterval). Therefore, it is safer to instantiate a new Date(), in order to always have the right time.

Also, it is posible to store the sequence of timers somewhere (ie, in an array), to allow modifying this sequence at any time, and also looping easily through it.

Following these points, I would have written something like the following code. Remember that this is an illustration, it might not produce your desired behavior.

var timeLoop = [5, 3, 5, 3, 5, 3, 5, 3, 7]; // seconds
var timeIterator = timeLoop.length;
var startTime;
var endTime;
var intervalTimer;

function sendTimer() { // once the timer ends, send it
    // send AJAX request with startTime and endTime here
}

function updateTimer() { // main timer loop
    var now = Date.now(); // make sure you have the right time
    var diff = endTime - now;
    if (diff <= 0) { // if endTime is past, stop and send the timer
        diff = 0;
        clearInterval(intervalTimer);
        sendTimer();
    }
    // Update the displayed time using diff (ms)
}

function resetTimer() { // to call on $("#reset").click
    if (endTime > Date.now()) {
        endTime = Date.now();
        updateTimer(); // reset the displayed time, and stop updateTimer
        // note that this will call sendTimer() with the _aborted_ time
    }
}

function startTimer() { // to call on $("#start").click
    resetTimer();
    // We will loop throught the timeLoop every time we start the timer
    if (timeLoop.length < ++timeIterator) {
        timeIterator = 0;
    }
    startTime = Date.now();
    endTime = startTime + 1000 * timeLoop[timeIterator];
    intervalTimer = setInterval(updateTimer, 500);
}
GnxR
  • 829
  • 1
  • 8
  • 20
  • Thank you for taking the time to respond to my question. I'm a bit out of my depth - I'm not sure how I can update the timer in my HTML. I bound the startTimer to a start-button, but when I click it - nothing happens. Would it be possible to display the information on html in the mm:ss format? – Cake Jun 11 '16 at 15:26
  • I am sorry if I was unclear. This code actually does nothing with the HTML document and only shows an usage of timers. I believe you can change according to your jQuery code to update HTML elements. The remaining time (in ms) is stored by `diff` in `updateTimer`; see [this question](http://stackoverflow.com/questions/1322732/convert-seconds-to-hh-mm-ss-with-javascript) about time formatting (from seconds, you will have to divide `diff` by 1000). – GnxR Jun 11 '16 at 15:46
  • Awesome. Thank you for your time. – Cake Jun 11 '16 at 15:49
  • If you want more explanations, don't hesitate to point out the dark parts of this answer or code. I might also update it to provide a more-working sample if you want to, although the changes to make are not related to timers. (I am sorry if I make some mistakes in English.) – GnxR Jun 11 '16 at 15:53
  • Your English is perfect, don't worry about that. I don't want to take advantage of anyone or seem to make someone else do my 'homework', but I am genuinely struggling with JavaScript. I haven't got enough time to properly learn JavaScript right now (there's a bit of a time constraint on this project). Could you, perhaps, give me a 'more-working sample'? One that could implement all the requested features and update the HTML timer in mm:ss? If that's too much too ask, I understand. – Cake Jun 11 '16 at 15:59
  • Done (I was a bit busy at the time), don't worry, it might be off-topic (loop + timers), but it is quick to do once you are used to JS, and I'm glad to help when I can. :) – GnxR Jun 11 '16 at 17:00
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/114430/discussion-between-cake-and-gnxr). – Cake Jun 11 '16 at 17:01