Search code examples
node.jsexpresshandlebars.js

How to display current time with node using express and handlebars


I'm trying to display the current time (including seconds) on my page, using node, express and handlebars. Naturally I want to avoid refreshing the page every second. I thought about using socket.io, getting the time every 30 seconds from the node server, and incrementing the seconds with javascript on the client side, but this approach strikes me as rather hacky. Is there a standardized solution for this problem?

EDIT:
So I kinda figured it out, but I'm not sure if this is efficient enough. Is there any way to maybe squeeze some more out of this code?

setInterval(function() {
    var time = Moment();
    if(time.seconds() === 0 || time.seconds() === 1) {
        io.emit('time', {
            time: time.format('HH:mm'),
            date: time.format('DD.MM.YYYY')
        });
    }
},1000);

Solution

  • After a lot of fiddling around and looking for the best way to do this, I stumbled over the concept of server sent events. Which is (explained in a very easy manner) like socket.io, but one way only - as the name suggests - from the server to the client. SSEs completely overate via HTTP, so no websockets needed.

    Middleware configuration:

    module.exports = function (req, res, next) {
        res.sseSetup = function() {
            res.writeHead(200, {
                'Content-Type': 'text/event-stream',
                'Cache-Control': 'no-cache',
                'Connection': 'keep-alive'
            });
            res.connection.setTimeout(10800000);
        };
    
        res.sseSend = function(data) {
            res.write("data: " + JSON.stringify(data) + "\n\n");
        };
    
        next();
    }
    

    Now register your middleware with express (usually in your app.js):

    app.use(require('./middlewares/sse'));
    

    and add the necessary routing handler:

    router.get('/time', function(req, res) {
        res.sseSetup();
        setInterval(function() {
            // create your time object - here: {time: 11:30:01}
            res.sseSend(timeObject);
        },1000);
    });
    

    Client side code:

    <script>
    if(!!window.EventSource) {
        var timeSource = new EventSource('/time');
        timeSource.addEventListener('message', function(event) {
            var data = JSON.parse(event.data);
            $('.time').text(data.time);
        }, false);
    }
    else {
        console.log("[ERROR](server) Your browser does not support SSE");
    }
    

    The data object in this case looks like this:

    {
        time: '11:30:01'
    }
    

    and can be extended/adjusted at will.

    Cheers!