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>
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.
Most helpful comment
Am relaxing.