0ui / elm-task-parallel / Task.Parallel

This library helps you run tasks in parallel when you only need the results if every task finishes successfully, similar to Promise.all() in Javascript. A good use case is handling the result of multiple HTTP requests.

Task Helpers

attempt2 : { task1 : Task x a, task2 : Task x b, onUpdates : Msg2 a b -> msg, onSuccess : a -> b -> msg, onFailure : x -> msg } -> ( State2 msg a b, Platform.Cmd.Cmd msg )

Attempt two tasks which will send an update when either all tasks finish successfully or one fails. The returned State will be used in your main update function to call update and pass internal messages.

type Msg
    = TaskStateUpdated (Task.Parallel.Msg2 String Int)
    | OneTaskFailed Http.Error
    | AllTasksCompleted String Int

doTask : ( Task.Parallel.State2 Msg String Int, Cmd Msg )
doTask =
    attempt2
        { task1 = fetchString
        , task2 = fetchInt
        , onUpdates = TaskStateUpdated
        , onFailure = OneTaskFailed
        , onSuccess = AllTasksCompleted
        }

attempt3 : { task1 : Task x a, task2 : Task x b, task3 : Task x c, onUpdates : Msg3 a b c -> msg, onSuccess : a -> b -> c -> msg, onFailure : x -> msg } -> ( State3 msg a b c, Platform.Cmd.Cmd msg )

attempt4 : { task1 : Task x a, task2 : Task x b, task3 : Task x c, task4 : Task x d, onUpdates : Msg4 a b c d -> msg, onSuccess : a -> b -> c -> d -> msg, onFailure : x -> msg } -> ( State4 msg a b c d, Platform.Cmd.Cmd msg )

attempt5 : { task1 : Task x a, task2 : Task x b, task3 : Task x c, task4 : Task x d, task5 : Task x e, onUpdates : Msg5 a b c d e -> msg, onSuccess : a -> b -> c -> d -> e -> msg, onFailure : x -> msg } -> ( State5 msg a b c d e, Platform.Cmd.Cmd msg )

attempt6 : { task1 : Task x a, task2 : Task x b, task3 : Task x c, task4 : Task x d, task5 : Task x e, task6 : Task x f, onUpdates : Msg6 a b c d e f -> msg, onSuccess : a -> b -> c -> d -> e -> f -> msg, onFailure : x -> msg } -> ( State6 msg a b c d e f, Platform.Cmd.Cmd msg )

attempt7 : { task1 : Task x a, task2 : Task x b, task3 : Task x c, task4 : Task x d, task5 : Task x e, task6 : Task x f, task7 : Task x g, onUpdates : Msg7 a b c d e f g -> msg, onSuccess : a -> b -> c -> d -> e -> f -> g -> msg, onFailure : x -> msg } -> ( State7 msg a b c d e f g, Platform.Cmd.Cmd msg )

attempt8 : { task1 : Task x a, task2 : Task x b, task3 : Task x c, task4 : Task x d, task5 : Task x e, task6 : Task x f, task7 : Task x g, task8 : Task x h, onUpdates : Msg8 a b c d e f g h -> msg, onSuccess : a -> b -> c -> d -> e -> f -> g -> h -> msg, onFailure : x -> msg } -> ( State8 msg a b c d e f g h, Platform.Cmd.Cmd msg )

attempt9 : { task1 : Task x a, task2 : Task x b, task3 : Task x c, task4 : Task x d, task5 : Task x e, task6 : Task x f, task7 : Task x g, task8 : Task x h, task9 : Task x i, onUpdates : Msg9 a b c d e f g h i -> msg, onSuccess : a -> b -> c -> d -> e -> f -> g -> h -> i -> msg, onFailure : x -> msg } -> ( State9 msg a b c d e f g h i, Platform.Cmd.Cmd msg )

attemptList : { tasks : List (Task x a), onUpdates : ListMsg a -> msg, onSuccess : List a -> msg, onFailure : x -> msg } -> ( ListState msg a, Platform.Cmd.Cmd msg )

Attempt a list of tasks which will update when all the tasks have finished or when one fails. Similar to a Task.sequence except in parallel.

type Msg
    = DownloadUpdated (Task.Parallel.ListMsg String)
    | DownloadFailed Http.Error
    | DownloadCompleted (List String)

fetchNames : ( ListState String, next )
fetchNames =
    attemptList
        { tasks = [ fetchFirstName, fetchSecondName, fetchThirdName ]
        , onUpdates = DownloadUpdated
        , onFailure = DownloadFailed
        , onSuccess = DownloadCompleted
        }

Less Common Helpers

attempt : (a -> msg) -> (x -> msg) -> Task x a -> Platform.Cmd.Cmd msg

Attempt a single task. The benefit of this over Task.attempt is that it handles routing the result to the provided success and failure messages. You can reuse those error messages for different tasks if they're handled the same way. Since there are no other tasks, you don't need to manage any additional updates.

type Msg
    = ErrorOcurred Http.Error
    | FetchCompleted MyData

doTask : Cmd Msg
doTask =
    attempt FetchCompleted ErrorOcurred fetchMyData

Update

You will have to pass internal messages and commands along in your update function in order to eventually get your results.

update2 : State2 msg a b -> Msg2 a b -> ( State2 msg a b, Platform.Cmd.Cmd msg )

Handle updates for two tasks by calling update2 inside of your main update function to keep this library's internal state updated. If they have either all finished successfully or one has failed, the corresponding message you provided will be sent to your main update function. Maintain a copy of the returned state to pass in on each subsequent update. This step is required with attempt[n] functions.

type Msg
    = DownloadUpdated (Task.Parallel.Msg2 Actor Film)
    | DownloadFailed Http.Error
    | DownloadCompleted Actor Film

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        DownloadUpdated taskMsg ->
            let
                ( nextTaskState, nextCmd ) =
                    Task.Parallel.update2 model.taskState taskMsg
            in
            ( { model | taskState = nextTaskState }, nextCmd )

        DownloadCompleted actor film ->
            ( { model | actor = actor, film = film, Cmd.none )

        DownloadFailed err ->
            ( { model | loadingError = Just err }, Cmd.none )

update3 : State3 msg a b c -> Msg3 a b c -> ( State3 msg a b c, Platform.Cmd.Cmd msg )

update4 : State4 msg a b c d -> Msg4 a b c d -> ( State4 msg a b c d, Platform.Cmd.Cmd msg )

update5 : State5 msg a b c d e -> Msg5 a b c d e -> ( State5 msg a b c d e, Platform.Cmd.Cmd msg )

update6 : State6 msg a b c d e f -> Msg6 a b c d e f -> ( State6 msg a b c d e f, Platform.Cmd.Cmd msg )

update7 : State7 msg a b c d e f g -> Msg7 a b c d e f g -> ( State7 msg a b c d e f g, Platform.Cmd.Cmd msg )

update8 : State8 msg a b c d e f g h -> Msg8 a b c d e f g h -> ( State8 msg a b c d e f g h, Platform.Cmd.Cmd msg )

update9 : State9 msg a b c d e f g h i -> Msg9 a b c d e f g h i -> ( State9 msg a b c d e f g h i, Platform.Cmd.Cmd msg )

updateList : ListState msg a -> ListMsg a -> ( ListState msg a, Platform.Cmd.Cmd msg )

Call updateList inside of your main update function to check if the tasks have failed or finished. Maintain a copy of the returned state to pass in on each subsequent updateList. This step is required with attemptList.

type Msg
    = DownloadUpdated (Task.Parallel.ListMsg Actor Http.Error)
    | DownloadFailed Http.Error
    | DownloadCompleted (List Actor)

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        DownloadUpdated taskMsg ->
            let
                ( nextTaskState, next ) =
                    Task.Parallel.updateList model.taskState taskMsg
            in
            ( { model | taskState = nextTaskState }, next )

        DownloadCompleted actors ->
            ( { model | actorList = actors, Cmd.none )

        DownloadFailed err ->
            ( { model | loadingError = Just err }, Cmd.none )

Types


type State2 msg a b

Opaque type for storing state of tasks.


type State3 msg a b c


type State4 msg a b c d


type State5 msg a b c d e


type State6 msg a b c d e f


type State7 msg a b c d e f g


type State8 msg a b c d e f g h


type State9 msg a b c d e f g h i


type Msg2 a b

Opaque type for updating state of tasks.


type Msg3 a b c


type Msg4 a b c d


type Msg5 a b c d e


type Msg6 a b c d e f


type Msg7 a b c d e f g


type Msg8 a b c d e f g h


type Msg9 a b c d e f g h i


type ListState msg a

Opaque type for storing state of task lists.


type ListMsg a

Opaque type for updating state of task lists.