11 Nov 2017, 15:00

Replicating JavaScripts setTimeout and setInterval in Go

In JavaScript we have two inbuilt functions for doing some work at some given point in the future. Firstly setTimeout; this allows us to run a function after a given period of time in milliseconds. We also have setInterval which allows us to run a function every x milliseconds until the interval is cancelled with clearInterval. You can find a solid overview of timers in JavaScript on MDN here.

For those unfamiliar with the two functions, let’s see how they look (in ES5):

    var timeout = 1000; // 1 second

        console.log("This will happen after " + timeout + "milliseconds");

    var interval = 500; // 0.5 seconds

    var anInterval = setInterval(function(){
        console.log("This will happen after " + timeout + "seconds");

Recently I have been wanting to achieve the same thing in Go on a small side project I am working on. As such I thought I would share my findings with you all!

Replicating setInterval

setInterval is arguably the more complicated of the two functions to implement. The basic premise is we setup a new ticker from Go’s time package. The NewTicker function creates a channel which we can select over (see here for an overview of the select feature in Go), which passes a signal to the channel every x milliseconds, calling the arbitrary passed in function. We also select over the clear channel. This can in turn clear the interval when we pass a boolean value to it.

    func setInterval(someFunc func(), milliseconds int, async bool) chan bool {

        // How often to fire the passed in function 
        // in milliseconds
        interval := time.Duration(milliseconds) * time.Millisecond

        // Setup the ticket and the channel to signal
        // the ending of the interval
        ticker := time.NewTicker(interval)
        clear := make(chan bool)

        // Put the selection in a go routine
        // so that the for loop is none blocking
        go func() {
            for {

                select {
                case <-ticker.C:
                    if async {
                        // This won't block
                        go someFunc()
                    } else {
                        // This will block
                case <-clear:


        // We return the channel so we can pass in 
        // a value to it to clear the interval
        return clear


    func main() {

        // A counter for the number of times we print
        printed := 0
        // We call set interval to print Hello World forever
        // every 1 second
        interval := setInterval(func() {
            fmt.Println("Hello World")
        }, 1000, false)
        // If we wanted to we had a long running task (i.e. network call)
        // we could pass in true as the last argument to run the function
        // as a goroutine

        // Some artificial work here to wait till we've printed
        // 5 times
        for {
            if printed == 5 {
                // Stop the ticket, ending the interval go routine
                stop <- true


Replicating setTimeout

Replicating JavaScripts setTimeout is slightly more straight forward. We can leverage the time package’s AfterFunc function which fires off goroutine that will run a function after a given period of time. We could do this using code like this:

    func setTimeout(someFunc func(), milliseconds int) {

        timeout := time.Duration(milliseconds) * time.Millisecond

        // This spawns a goroutine and therefore does not block
        time.AfterFunc(timeout, someFunc)


    func main() {

        printed := false
        print := func() {
            fmt.Println("This will print after x milliseconds")
            printed = true

        // Make the timeout print after 5 seconds
        setTimeout(print, 5000)

        fmt.Println("This will print straight away")
        // Wait until it's printed our function string
        // before we close the program
        for {
            if printed {

Hopefully this has given some insight on how we might achieve similar functionality in Go to JavaScripts setInterval and setTimeout functionality. If you see a potential problem, or have ideas about a better solution I would love to hear them!

comments powered by Disqus