Clearing Timers

📝 We continue in the Speedy Chef project folder throughout this section.

Available methods

This section has covered the setTimeout and setInterval methods. Both methods also have a clear counterpart too, we have clearTimeout and clearInterval.

These clear methods will stop the timers when we no longer need them to run. This is useful for when the game is over. We can stop things like the countdown so we can re start when needed, and not use up the browser’s resources unnecessarily.

Storing a reference to the timer

To be able to clear a timer, we first need to store the original timer into a variable:

let orderTimerRef = ''; // order timer
function ordersTimer() {
  setInterval(generateNewOrder, 3000);
}

let countdownTimerRef = ''; // countdown timer
function countdownTimer() {
  countdownTime - 1;
  document.querySelector(
    '#gameLength'
  ).innerText = `Time left: ${countdownTime--}`;
}

let gameTimerRef = ''; // game timer
function gameTimer() {
  setTimeout(endOfGame, gameLength * 1000);
}

These variables are placed next to the functions, but they can go anywhere you prefer. Then assign the timers to these variables, only two of these functions hold the timers, so we can set these now:

let orderTimerRef = '';
function ordersTimer() {
  // store timer in orderTimerRef
  orderTimerRef = setInterval(generateNewOrder, 3000);
}
let gameTimerRef = '';
function gameTimer() {
  // store timer in gameTimerRef
  gameTimerRef = setTimeout(endOfGame, gameLength * 1000);
}

Note how we declare these let variables outside of the function. This is because if we declare them inside of the function, we could not access them in other parts of our code, and we need them soon to clear the timers. We will cover this in more detail in a later section.

The countdownTimer function does not contain the timeout, so we need to go to the startOfGame function and set it there:

function startOfGame() {
    // store existing setInterval into the countdownTimerRef variable
    countdownTimerRef = setInterval(countdownTimer, 1000);
  // ...

When we start the game, we should see our timers are working, the game time is counting down, and the orders are coming in. But, if we click on the end button, the timers keep running. The orders still generate and the countdown continues.

Clearing the game timers

These timers can now be cleared when we call the endOfGame function:

function endOfGame() {
  gameStarted = false;
  // Clear all three timers:
  clearInterval(orderTimerRef);
  clearInterval(countdownTimerRef);
  clearTimeout(gameTimerRef);
  document.querySelector('#endBtn').style.display = 'none';
  document.querySelector('#startBtn').style.display = 'inline';
}

Try this again and the timers should stop when we click the end button. If we click start again, the timers continue from where they left off. We will do some clean up work soon to fix these issues.

Completed code after this lesson

If needed, here is the completed code we added to the starter file (index.js):

let oven = [];
const ovenCapacity = 6;
let pizzasCompleteForOrder = 0;
let gameStarted = false;
const gameLength = 300;
let countdownTime = gameLength;
document.querySelector(
    "#gameLength"
).innerText = `Game length is ${gameLength} seconds`;
document.querySelector("#endBtn").style.display = "none";

function buildElement(elementName, elementContent) {
    const element = document.createElement(elementName);
    const content = document.createTextNode(elementContent);
    element.appendChild(content);
    return element;
}

function createListOfPizzas(pizzas) {
    const pizzaList = document.createElement("ul");
    pizzas.forEach(function (pizza) {
        const orderQuantityEl = buildElement("span", `${pizza.quantity} - `);
        const pizzaNameElement = buildElement("span", pizza.name);
        pizzaNameElement.classList.add("pizza_name");
        const pizzaItem = document.createElement("li");
        pizzaItem.append(orderQuantityEl, pizzaNameElement);
        pizzaList.appendChild(pizzaItem);
    });
    return pizzaList;
}

function createSingleOrder(order) {
    const orderWrapper = document.createElement("div");
    orderWrapper.className = "order_wrapper";
    orderWrapper.addEventListener("click", selectCurrentOrder);
    const orderNumberEl = buildElement("h4", `Order: ${order.id}`);
    orderWrapper.appendChild(orderNumberEl);
    const pizzaList = createListOfPizzas(order.pizzas);
    orderWrapper.appendChild(pizzaList);
    return orderWrapper;
}

function createOrdersList() {
    document.querySelector("#orders").innerHTML = "";
    orders.forEach(function (order) {
        const singleOrder = createSingleOrder(order);
        document.querySelector("#orders").appendChild(singleOrder);
    });
}

function selectCurrentOrder(e) {
    const pizzas = document.querySelectorAll(".pizza_name");
    pizzas.forEach(function (pizza) {
        pizza.addEventListener("click", setCurrentPizza);
    });

    if (document.querySelector("#working_on").children.length > 1) {
        return;
    }
    let element = e.target;
    const orderWrapper = element.closest(".order_wrapper");
    if (orderWrapper !== null) {
        orderWrapper.removeEventListener("click", selectCurrentOrder);
        const orderDiv = document.querySelector("#working_on");
        orderDiv.appendChild(orderWrapper);
    }
}

function setCurrentPizza(e) {
    const pizzaName = e.target.innerText;
    document.querySelector("#current_pizza").innerText = pizzaName;
    displayMethod(pizzaName);
}

function displayMethod(pizzaName) {
    document.querySelector("#pizza_name").innerText = pizzaName;
    const selectedPizza = pizzas.find((pizza) => pizza.name === pizzaName);
    const methodSteps = selectedPizza.method.split(".");
    document.querySelector("#pizza_method").innerHTML = "";
    methodSteps.forEach(function (method) {
        const element = buildElement("li", method);
        document.querySelector("#pizza_method").appendChild(element);
    });
}

function addToOven() {
    pizzasCompleteForOrder++;
    const pizzaName = document.querySelector("#current_pizza").innerText;
    if (pizzaName) {
        const pizzaForOven = {
            name: pizzaName,
            timeAdded: "5/5/28",
        };
        oven.push(pizzaForOven);
        displayOvenItems();
    }
}

document.querySelector("#addToOven").addEventListener("click", addToOven);

function displayOvenItems() {
    document.querySelector("#oven").innerHTML = "";
    oven.forEach(function (pizza) {
        const pizzaDiv = document.createElement("div");
        pizzaDiv.className = "pizza_div";
        const image = document.createElement("img");
        image.src = "pizza.svg";
        const pizzaName = buildElement("p", `(${pizza.name})`);
        pizzaDiv.append(image, pizzaName);
        document.querySelector("#oven").appendChild(pizzaDiv);
    });
}

function startOfGame() {
    if (gameStarted) {
        return;
    }
    document.querySelector("#startBtn").style.display = "none";
    document.querySelector("#endBtn").style.display = "inline";

    gameStarted = true;
    const orders = document.getElementsByClassName("order_wrapper");
    Array.from(orders).forEach(function (order) {
        order.remove();
    });
    createOrdersList();
    ordersTimer();
    countdownTimerRef = setInterval(countdownTimer, 1000);
    gameTimer();

    document.querySelector("#message").innerText =
        "Chef, our first orders are coming in!!!";
    setTimeout(function () {
        document.querySelector("#message").innerText = "";
    }, 3000);
}

function endOfGame() {
    gameStarted = false;
    clearInterval(orderTimerRef);
    clearInterval(countdownTimerRef);
    clearTimeout(gameTimerRef);
    document.querySelector("#endBtn").style.display = "none";
    document.querySelector("#startBtn").style.display = "inline";
}
document.querySelector("#startBtn").addEventListener("click", startOfGame);
document.querySelector("#endBtn").addEventListener("click", endOfGame);

let orderNumber = orders.length + 1;

function generateNewOrder() {
    let pizzas = [];
    const orderItem = Math.ceil(Math.random() * 5);
    for (i = 1; i <= orderItem; i++) {
        pizzas.push(generateNewPizza());
    }
    const newOrder = {
        id: orderNumber,
        pizzas,
    };
    orders.push(newOrder);
    orderNumber++;

    createOrdersList();
}

function generateNewPizza() {
    const quantity = Math.ceil(Math.random() * 3);
    const randomPizza = pizzas[Math.floor(Math.random() * pizzas.length)];
    const pizza = {
        quantity,
        name: randomPizza.name,
    };
    return pizza;
}
generateNewPizza();

let orderTimerRef = "";
function ordersTimer() {
    orderTimerRef = setInterval(generateNewOrder, 3000);
}

let countdownTimerRef = "";
function countdownTimer() {
    countdownTime -= 1;
    document.querySelector(
        "#gameLength"
    ).innerText = `Time left: ${countdownTime}`;
}

let gameTimerRef = "";
function gameTimer() {
    gameTimerRef = setTimeout(endOfGame, gameLength * 1000);
}