常规和关闭频道的异常行为

According to Golang Documentation,

A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns. Defer is commonly used to simplify functions that perform various clean-up actions.

In other words, go defer temporarily holds the execution of command until the surrounding function returns. I wrote a simple go program which contains several goroutines, which should terminate 8 reader goroutines upon the termination of the looper goroutine.

func main(){
    // declaring handler
    handler := make(chan int)

    var wg sync.WaitGroup

    // execute reader as 8 separate processes
    for i := 0; i < 8; i++ {
        go reader(handler, &wg)
    }

    // timer which fires an event once in a second
    ticker := time.NewTicker(1 * time.Second)

    // the channel which carries out termination signal
    terminator := make(chan interface{})

    go looper(ticker.C, handler, terminator)

    // wait for 5 Seconds
    time.Sleep(time.Second * 5)

    // terminate looper
    close(terminator)

    //wait for reader functions to do their work
    wg.Wait()
}

// receive val from looper and process it
func reader(handler <-chan int, wg *sync.WaitGroup) {
    wg.Add(1)
    defer wg.Done()
    for val := range handler {
        fmt.Printf("Received %d
", val)
        time.Sleep(2 * time.Second) //just to simulate a lengthy process
    }
}

in the program, if I close the handler channel using defer, it works fine.

func looper(ticker <-chan time.Time, handler chan<- int, terminator <-chan interface{}) {
    arr := []int{1, 2, 3, 4, 5}
    defer close(handler)
    for {
        select {
        case <-ticker:
            for _, val := range arr {
                // passed the index to communication channel
                handler <- val
            }
        case <-terminator:
            return
        }
    }
}

But if I close the handler channel just before the return statement as follows, the program exists without printing anything

func looper(ticker <-chan time.Time, handler chan<- int, terminator <-chan interface{}) {
    arr := []int{1, 2, 3, 4, 5}
    for {
        select {
        case <-ticker:
            for _, val := range arr {
                // passed the val to reader
                handler <- val
            }
        case <-terminator:
            close(handler)
            return
        }
    }
}

What could be the root cause? I'm just having a BIG confusion there.