-
Notifications
You must be signed in to change notification settings - Fork 358
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Order of port declarations influences behaviour #896
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. |
Note that - and this is the truly unexpected part - flipping the order in which the ports are declared fixes this issue, since this directly corresponds to the order in the https://ellie-app.com/3YKLTxbsg7na1/2 (only difference with Subs first means subscriptions will be processed firstport toElm : (String -> msg) -> Sub msg
port toJS : String -> Cmd msg Subs last means subs will be processed last.port toJS : String -> Cmd msg
port toElm : (String -> msg) -> Sub msg The order in which ports are declared really should not impact behaviour. |
Thank you for the SSCCE! It looks like the fix for conditional subscriptions in 704dcc0 works for this case as well. I updated the code for 0.19.1 and tried it with my local version of elm/core and it seems to be working as expected now. The fix should be available in 1.0.3 along with some other improvements. Here is the updated SSCCE since I have it right now: <html>
<head>
<script src="elm.js"></script>
</head>
<body>
<script>
var app = Elm.Bug.init();
app.ports.toJS.subscribe(function (value) {
console.log("Received", value);
app.ports.toElm.send(value);
});
</script>
</body>
</html> port module Bug exposing (..)
import Browser
import Html exposing (..)
import Html.Events exposing (onClick)
type alias Model =
{ receiving : Bool, received : String }
type Msg
= Enable
| Receive String
port toJS : String -> Cmd msg
port toElm : (String -> msg) -> Sub msg
init : () -> ( Model, Cmd msg )
init _ =
( Model False "", Cmd.none )
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Enable ->
( { model | receiving = True }, toJS "marker" )
Receive val ->
( { model | received = val }, Cmd.none )
subscriptions : Model -> Sub Msg
subscriptions { receiving } =
if receiving then
Receive |> toElm
else
Sub.none
view : Model -> Browser.Document Msg
view { received } =
{ title = "Bug"
, body =
[ text description
, br [] []
, button [ onClick Enable ] [ text "send it and enable receiving" ]
, br [] []
, text <| "Received: " ++ received
]
}
main : Program () Model Msg
main =
Browser.document
{ init = init
, update = update
, view = view
, subscriptions = subscriptions
}
description : String
description =
"""
Upon pressing the button, a message is sent to JS which is then synchronously dispatched back to Elm. Since subscription-handlers aren't scheduled strictly before sending out commands, this message is dropped.
""" |
SSCCE
https://ellie-app.com/3YKLTxbsg7na1/1
TL;DR
send
update
which modifies the model to enable a subscription and triggers that outgoing portsend
is called before the subscription handler is scheduled, hence dropping the message.Problem statement
Setting state to enable a subcription and triggering an outgoing port which synchronously calls back into Elm at the same time leads to this response being missed. This can easily come up when using a subscription-structure like advocated by elm-spa-example.
This is surprising since the user has already configured their model so that a subscription should be enabled, and how/when those subscriptions actually go into effect is an implementation detail the user shouldn't need to worry about.
Possible fix
Ensuring that subscription handlers are scheduled before commands are scheduled seems like a fix; I'm not sure if there are potential adverse effects to doing so.
The text was updated successfully, but these errors were encountered: