WebsiteRacer
的函数,用来对比请求两个 URL 来「比赛」,并返回先响应的 URL。如果两个 URL 在 10 秒内都未返回结果,那么应该返回一个 error
。net/http
用来调用 HTTP 请求net/http/httptest
用来测试这些请求select
用来同步进程./racer_test.go:14:9: undefined: Racer
racer_test.go:25: got '', want 'http://www.quii.co.uk'
time.Now()
来记录请求 URL
前的时间。time.Since
获取开始时间并返回一个 time.Duration
时间差。httptest.NewServer
接受一个我们传入的 匿名函数 http.HandlerFunc
。http.HandlerFunc
是一个看起来类似这样的类型:type HandlerFunc func(ResponseWriter, *Request)
。ResponseWriter
和 Request
参数的函数,这对于 HTTP 服务器来说并不奇怪。httptest.NewServer
,它会找一个可监听的端口,然后测试完你就可以关闭它了。time.Sleep
一段时间,当我们请求时让它比另一个慢一些。然后两个服务器都会通过 w.WriteHeader(http.StatusOK)
返回一个 OK
给调用者。Racer
函数更加易读。makeDelayedServer
的函数重构了模拟服务器,以将一些不感兴趣的代码移出测试并减少了重复代码。defer
defer
前缀会在 包含它的函数结束时 调用它。select
的新构造(construct),它可以帮我们轻易清晰地实现进程同步。ping
chan bool
类型并返回它的 ping
函数。http.Get(url)
时启动了一个用来给 channel 发送信号的 Go 程(goroutine)。select
myVar := <-ch
来等待值发送给 channel。这是一个 阻塞 的调用,因为你需要等待值返回。select
则允许你同时在 多个 channel 等待。第一个发送值的 channel「胜出」,case
中的代码会被执行。select
中使用 ping
为两个 URL
设置两个 channel。无论哪个先写入其 channel 都会使 select
里的代码先被执行,这会导致那个 URL
先被返回(胜出)。Racer
耗时超过 10 秒时返回一个 error。_
忽略掉了)和一个 error
。./racer_test.go:37:10: assignment mismatch: 2 variables but 1 values
Racer
的函数签名来返回胜出者和一个 error
。返回 nil
仅用于模拟顺利的场景(happy cases)。got, _ := Racer(slowURL, fastURL)
,要知道顺利的场景中我们不应得到一个 error
。select
时,time.After
是一个很好用的函数。当你监听的 channel 永远不会返回一个值时你可以潜在地编写永远阻塞的代码,尽管在我们的案例中它没有发生。time.After
会在你定义的时间过后发送一个信号给 channel 并返回一个 chan
类型(就像 ping
那样)。a
或 b
谁胜出就返回谁,但如果测试达到 10 秒,那么 time.After
会发送一个信号并返回一个 error
。Racer
(使用 ConfigurableRacer
),不顺利的场景测试可以使用 ConfigurableRacer
。error
。select
time.After
来防止你的系统被永久阻塞。httptest
net/http
相同的接口作为「真实的」服务器会和真实环境保持一致,并且只需更少的学习。