skip to Main Content

I made a clock. I realized that when I switch another tab and came back after a while the clock stop behind current time. I found something named web workers, is it related to this??
Same senteces, don’t read. I made a clock. I realized that when I switch another tab and came back after a while the clock stop behind current time. I found something named web workers, is it related to this??

I expected the code work anytime but it didn’t.
The code:

let numbers = document.getElementsByClassName('number');
let numbersLength = numbers.length-1; 
let numberContainer = document.querySelectorAll('.number > div');
let minute = document.querySelector('#minute');
let hour = document.querySelector('#hour');
let second = document.querySelector('#second');
let startSecond = new Date().getSeconds()*6;
let startHour = new Date().getHours()*30;
let startMinute = new Date().getMinutes()*6;


setInterval(increaseSecond, 1000);

function readyHour() {
    //second starting position
    second.style.transform = `rotate(${startSecond}deg)`;
    minute.style.transform = `rotate(${startMinute}deg)`;
    hour.style.transform = `rotate(${startHour}deg)`;
    
    //numbers positions
    for(let i = 0; i <= numbersLength; i++){
        numbers[i].style.transform = `rotate(${i*30}deg)`;
        numberContainer[i].style.transform = `rotate(${-(i*30)}deg)`;
    }
}
readyHour();

function increaseSecond(){
    let currentSecond = new Date().getSeconds();
    let currentMinute = new Date().getMinutes();
    let currentHour = new Date().getHours();

    second.style.transform = `rotate(${currentSecond*6}deg)`;
    if(currentSecond === 0){
        minute.style.transform = `rotate(${currentMinute*6}deg)`;
    };

    if(currentMinute === 0)
        hour.style.transform = `rotate(${currentHour*30}deg)`;
        
}
*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}
body{
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
}
.clock{
    background-color: black;
    height: 350px;
    width: 350px;
    display: flex;
    justify-content: center;
    align-items: center;
    border-radius: 50%;
    position: relative;
    border: 8px solid #31e1e7;
}

.number{
    font-size: 3rem;
    color: #ffffff;
    text-align: center;
    position: absolute;
    height: 100%;
    width: 100%;
}

.hand{
    position: absolute;
    left: 49.2%;
    bottom: 50%;
    width: 3px;
    background-color: red;
    transform-origin: bottom;
}
#second{
    z-index: 10;
    height: 120px;
}
#minute{
    height: 110px;
}

#hour{
    height: 65px;
}

#clock-center{
    background-color: #ffffff;
    height: 15px;
    width: 15px;
    z-index: 11;
    border-radius: 50%;
    position: absolute;
}
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="assets/main.css">
</head>
<body>
    
</head>
<body>
    <div class="clock">
        <div id="clock-center"></div>
        <div class="hand " id="minute"></div>
        <div class="hand " id="hour"></div>
        <div class="hand" id="second"></div>
        
        <div class="number"><div>12</div></div>
        <div class="number"><div>1</div></div>
        <div class="number"><div>2</div></div>
        <div class="number"><div>3</div></div>
        <div class="number"><div>4</div></div>
        <div class="number"><div>5</div></div>
        <div class="number"><div>6</div></div>
        <div class="number"><div>7</div></div>
        <div class="number"><div>8</div></div>
        <div class="number"><div>9</div></div>
        <div class="number"><div>10</div></div>
        <div class="number"><div>11</div></div>
    </div>
    
    <script src="assets/main.js"></script>
</body>
</html>

2

Answers


  1. Browsers often optimize background tabs to use fewer resources, which can include throttling or stopping JavaScript execution. In your case, using a Web Worker can indeed solve this problem. A Web Worker runs in the background independently of the main JavaScript thread and continues executing even if the tab is not active.

    Here’s how you can implement your clock using a Web Worker:

    worker.js (The Web Worker script)

    let startSecond = new Date().getSeconds() * 6;
    let startHour = new Date().getHours() * 30;
    let startMinute = new Date().getMinutes() * 6;
    
    function increaseSecond() {
        let currentSecond = new Date().getSeconds();
        let currentMinute = new Date().getMinutes();
        let currentHour = new Date().getHours();
    
        postMessage({
            second: currentSecond,
            minute: currentMinute,
            hour: currentHour
        });
    
        setTimeout(increaseSecond, 1000);
    }
    
    increaseSecond();
    

    main.js

    let worker = new Worker('worker.js');
    
    worker.onmessage = function(event) {
        let currentSecond = event.data.second;
        let currentMinute = event.data.minute;
        let currentHour = event.data.hour;
    
        second.style.transform = `rotate(${currentSecond * 6}deg)`;
        if (currentSecond === 0) {
            minute.style.transform = `rotate(${currentMinute * 6}deg)`;
        }
    
        if (currentMinute === 0) {
            hour.style.transform = `rotate(${currentHour * 30}deg)`;
        }
    };
    
    worker.postMessage(null); // Start the worker.
    

    In this setup:

    1. worker.js contains the logic for updating the clock’s time. It runs independently in the background.
    2. main.js creates a new Web Worker and listens for messages from the worker. When the worker updates the time, it sends a message to the main thread, which then updates the clock accordingly.

    Using a Web Worker ensures that your clock continues to run even if the tab is not active. Remember to adjust the paths to your worker script and include the appropriate HTML structure for your clock elements.

    Login or Signup to reply.
  2. The problem you face is not so much related to the inactivity of the browser page and that timer ticks are suspended. Once the page comes into view again, these ticks resume immediately, so there should be opportunity for your code to display the clock correctly on those ticks.

    The problem is really caused by the fact that your code only updates the minute hand when a minute has passed, and the hour hand only updates when an hour has passed. This practically means that when you come back to the page after a long period of activity, the minute and hour hand will not be updated until enough time has passed, and will appear wrong during that time.

    The solution is simple: always update the display of all three hands, unconditionally, at every tick of setInterval.

    So change this:

        if(currentSecond === 0){
            minute.style.transform = `rotate(${currentMinute*6}deg)`;
        };
    
        if(currentMinute === 0)
            hour.style.transform = `rotate(${currentHour*30}deg)`;
    

    to this:

        minute.style.transform = `rotate(${currentMinute*6}deg)`;
        hour.style.transform = `rotate(${currentHour*30}deg)`;
    

    This will fix the issue.

    More remarks

    I find it not intuitive that the hour hand moves with steps of 30 degrees. That means that when it is one minute to 12, the hour hand still points to 11, giving the false impression it is one minute to 11.

    To a lesser extent this also applies to the minute hand: it could move with smaller steps than 6 degrees giving a more fluent display.

    Here is how I would change it:

    const minute = document.querySelector('#minute');
    const hour = document.querySelector('#hour');
    const second = document.querySelector('#second');
    
    function setNumbers() {
        const numbers = document.getElementsByClassName('number');
        const numberContainer = document.querySelectorAll('.number > div');
        for (let i = 0; i < numbers.length; i++) {
            numbers[i].style.transform = `rotate(${i*30}deg)`;
            numberContainer[i].style.transform = `rotate(${-(i*30)}deg)`;
        }
    }
    
    function refresh() {
        const now = new Date();
        const currentSecond = now.getSeconds();
        const currentMinute = now.getMinutes();
        const currentHour   = now.getHours();
    
        second.style.transform = `rotate(${currentSecond*6}deg)`;
        minute.style.transform = `rotate(${currentMinute*6+currentSecond/10}deg)`;
        hour.style.transform   = `rotate(${currentHour*30 + currentMinute/2}deg)`;
    }
    
    setNumbers();
    refresh();
    setInterval(refresh, 1000);
    *{
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    body{
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
    }
    .clock{
        background-color: black;
        height: 350px;
        width: 350px;
        display: flex;
        justify-content: center;
        align-items: center;
        border-radius: 50%;
        position: relative;
        border: 8px solid #31e1e7;
    }
    
    .number{
        font-size: 3rem;
        color: #ffffff;
        text-align: center;
        position: absolute;
        height: 100%;
        width: 100%;
    }
    
    .hand{
        position: absolute;
        left: 49.2%;
        bottom: 50%;
        width: 3px;
        background-color: red;
        transform-origin: bottom;
    }
    #second{
        z-index: 10;
        height: 120px;
    }
    #minute{
        height: 110px;
    }
    
    #hour{
        height: 65px;
    }
    
    #clock-center{
        background-color: #ffffff;
        height: 15px;
        width: 15px;
        z-index: 11;
        border-radius: 50%;
        position: absolute;
    }
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <link rel="stylesheet" href="assets/main.css">
    </head>
    <body>
        
    </head>
    <body>
        <div class="clock">
            <div id="clock-center"></div>
            <div class="hand " id="minute"></div>
            <div class="hand " id="hour"></div>
            <div class="hand" id="second"></div>
            
            <div class="number"><div>12</div></div>
            <div class="number"><div>1</div></div>
            <div class="number"><div>2</div></div>
            <div class="number"><div>3</div></div>
            <div class="number"><div>4</div></div>
            <div class="number"><div>5</div></div>
            <div class="number"><div>6</div></div>
            <div class="number"><div>7</div></div>
            <div class="number"><div>8</div></div>
            <div class="number"><div>9</div></div>
            <div class="number"><div>10</div></div>
            <div class="number"><div>11</div></div>
        </div>
        
        <script src="assets/main.js"></script>
    </body>
    </html>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search