Core: Port interactions do not preserve the order of Cmd.batch

Created on 30 Dec 2016  路  8Comments  路  Source: elm/core

I have noticed that Elm 0.18 does not respect the order of port interactions defined by Cmd.batch. This is a problem for me as I am writing an Elm web client which receives data with a series of events (log file), parses it, and dispatches a series of event to a Javascript module through Elm ports. Cmd.batch like this

  {} ! [ portA 5, portA 4, portB 3, portB 2, portA 1 ]

in Javascript console produces

Event [1] received through portA
Event [4] received through portA
Event [5] received through portA
Event [2] received through portB
Event [3] received through portB

As you can see first Javascript subscription handlers of Port A have been called, and then Port B, which broke the original ordering portA 5, portA 4, portB 3, portB 2, portA 1. Note: the test has been started after all subscriptions are in place (see elm.ports.triggerTest.send(null); line in index.html below). So the order of subscribing should not affect the observed behavior.

How to reproduce
All files are in https://github.com/lguminski/ElmOrderingPortEventsTest repository. Clone them

git clone https://github.com/lguminski/ElmOrderingPortEventsTest
cd ElmOrderingPortEventsTest
make

and open http://localhost:8000 in your browser and check logs in Javascript console.

Files

OrderingPortEventsTest.elm

port module Main exposing (..)
import Html exposing (..)
import Html.Attributes exposing (..)

type alias Model =
  {}

type Msg
  = NoOp
  | Test ()


main =
  Html.program
    { init = init
    , update = update
    , view = view
    , subscriptions = subscriptions
    }

view : Model -> Html Msg
view model =
  div [] []

subscriptions : Model -> Sub Msg
subscriptions model =
  Sub.batch [ triggerTest Test ]

port portA : Int -> Cmd msg
port portB : Int -> Cmd msg
port triggerTest : (() -> msg) -> Sub msg

init : ( Model, Cmd Msg )
init =
  {} ! []

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
  case msg of

    NoOp ->
      model ! []

    Test _ ->
      model  !  [ portA 5, portA 4, portB 3, portB 2, portA 1 ]

index.html

<!DOCTYPE html>
<html lang="en">
    <body>
        <script src="elm.js"></script>
        <script>
            const elm = Elm.Main.fullscreen();
            elm.ports.portA.subscribe((number) => {
                console.log("Event [" + number + "] received through portA")
            });
            elm.ports.portB.subscribe((number) => {
                console.log("Event [" + number + "] received through portB")
            });
            elm.ports.triggerTest.send(null);
        </script>
    </body>
</html>

Most helpful comment

Am relaxing.

All 8 comments

Thanks for the issue! Make sure it satisfies this checklist. My human colleagues will appreciate it!

Here is what to expect next, and if anyone wants to comment, keep these things in mind.

This is not a bug. The specification of Cmd.batch doesn't promise any order preservation. See the comments in https://github.com/elm-lang/core/issues/730.

Just hit this problem. Definitely an unexpected result. It should be documented in Cmd.batch that no effect order is guaranteed, although mine appeared to be last-to-first.

The following gives the expected behaviour (notice the reverse):

 -- | All tests.                                                                                          
 tests : Cmd Event
 tests = Cmd.batch <| List.reverse
         [ H.send (Res "register/") (register host guy)
         , H.send (Res "signin/") (signin host guy.uuid)
         , H.send (Res "groups/ (A)") (groups host <| BlockSignin A "Foo" [guy.uuid])
         , H.send (Res "groups/ (B)") (groups host <| BlockSignin B "Bar" [guy.uuid])
         , H.send (Res "groups/ (C)") (groups host <| BlockSignin C "Baz" [guy.uuid])
         ]

@fosskers, as explained above and in #730, this is not a bug. If you think it is something that should be documented better/differently, a comment in this closed issue here will probably not help much. What might help is a new issue or PR calling for such a concrete documentation change.

It may not be a bug, but the "feature behaviour" is unexpected, and documenting as such in old issues is helpful for future devs, I've found. The more people that report the behaviour, the better.

So you say it "should be documented in Cmd.batch", but are unwilling to open an issue or PR that would work toward that goal? (The issue here is not working toward that goal of adding information to the documentation of Cmd.batch.)

Relax Janis ;)

Am relaxing.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zwilias picture zwilias  路  4Comments

EuAndreh picture EuAndreh  路  3Comments

liamcurry picture liamcurry  路  4Comments

opvasger picture opvasger  路  6Comments

dullbananas picture dullbananas  路  3Comments