elm / http

Make HTTP requests in Elm
https://package.elm-lang.org/packages/elm/http/latest
BSD 3-Clause "New" or "Revised" License
155 stars 46 forks source link

Example where parallel requests may be ideal #52

Open j-maas opened 5 years ago

j-maas commented 5 years ago

As proposed in #28, I would like to gather examples of where parallel requests are ideal. This issue is also discussed on Discourse.

In my case I want to fetch multiple xkcd comics in parallel. I have a function that generates a list of the N most recent xkcds by fetching the current one, and making a list of ids starting with the current one's. Then I can map that list of ids to requests that fetch the actual xkcd comic.

Currently, this is implemented using Task.sequence. But obviously, there would be a huge performance boost if there was a way to execute all requests in parallel. And it would be tough to do it with separate Cmds, because I would need to know when the last response has finished, which means somehow counting how many have already come back.

As for the error handling problem: I imagine a function Http.parallel : List Http.Request -> Task Http.Error (List Http.Response) (where Http.Request can't be a Cmd, I guess, but basically what Http.get or Http.request would return). Because those Http.Responses encode all possible errors, I can then choose how to deal with them. In my case I will probably ignore them. For example:

evaluateResponses : List Http.Response -> List Xkcd
evaluateResponses responses =
    List.foldl (\response evaluated ->
        case response of
            Http.GoodStatus_ meta body ->
                evaluated ++ [
                    -- Returns an Xkcd
                    Xkcd.parseBody body
                 ]

            -- Ignore errors
            _ ->
                evaluated
michaeljones commented 5 years ago

I hope it is ok to add to this issue. I can break it out as a separate one if desirable.


I have a situation at work where I'm loading a 'teams' page for a 'campaign' and I need to load the campaign information to get the name & associated team ids and I need to load all the teams so that I can provide a full list of possible teams to assign to the campaign.

I would like these requests to happen in parallel to minimise any delay when loading the page. I do not wish to use Cmds as I would like to be able to wait on the result and only change the page to the 'teams' page once all the data has arrived to avoid a 'loading' screen briefly appearing whilst the Http requests are made. I am happy with a Task.map2 style interface.

I feel like I would prefer to be able to execute these in parallel and deal with the result as I am not interested in the details if either one fails. A simple 'failed to load' message would be sufficient as it is unlikely to occur.

I confess I have not tried an approach where I use commands and then manage the logic in the update function to figure out when all the data has arrived for a page and only then set the page. That feels very tedious and awkward to scale across multiple pages. I also understand that 'I expect that to be tedious' is not the greatest argument.

alex-tan commented 5 years ago

I would like to second @michaeljones scenario. This is a very common pattern we use in almost every Elm application/element in our company where there are several (in one case up 10) requests made to fetch data before the application displays the main interface. (Until then it just displays a loading screen).

I created a package to load all the initial data using Task.map[n] and then have the core logic of the application not need to deal with any Maybe or other optional types which greatly reduces the complexity of both the views and the update function.

Having those requests be able to load in parallel with a function mirroring Task.map[n] would be very nice.

jjant commented 4 years ago

We do the same here, having to do this with commands would be a huge pain