> There are major performance advantages
You didn't outline the performance advantage. You've got "you need to create entire async thunks or threads to fill that data in", but that absolutely isn't true.
Let's look at how we might stream a file in response in go with the current model vs this new model, and you can point out where the performance difference is:
// current
func responseHandler(rw http.ResponseWriter, req *http.Request) {
fi, err := os.OpenFile("/tmp/file")
if err != nil {
rw.WriteHeader(500)
rw.Write([]byte("error opening file"))
}
io.Copy(rw, fi)
fi.Close()
}
// returning a streaming Response object
func responseHandler(req *http.Request) *http.HandlerResponse {
fi, err := os.OpenFile("/tmp/file")
if err != nil {
return &http.HandlerResponse{Status: 500, Body: ioutil.NopCloser(bytes.NewReader([]byte("error opening file"))}
}
return &http.HandlerResponse{Status: 200, Body: fi}
}
In the happy path, there's no difference in number of goroutines or anything, right? In both cases, this all runs in the goroutine or thread or whatever that the caller _already_ created for the request handler. What difference does it make if the request handler calls `io.Copy(response, body)` or if your function does, in both case it's the same goroutine/thread.
> You have also gained ~nothing.
You were the one that claimed you lose massive performance, and that's what we're asking about. The ergonomics are a separate thing from performance