Elm Outgoing Port Message Delivery Without a JavaScript Subscriber
0 reputation · 07 Jan 2020, 05:54 UTC
0 reputation · 07 Jan 2020, 05:54 UTC
Assumes Elm 0.19.1. The goal is to send a value through an Elm outgoing port and determine whether the Elm runtime can detect when no JavaScript subscriber is listening.
Outgoing ports push values to JavaScript asynchronously using JSON serialization. Elm cannot block for a response, and the compiler does not require a host-side subscription. Messages sent to an unsubscribed port are reportedly dropped silently, but it is unclear whether Elm provides a diagnostic, buffer, or delivery confirmation for the caller.
35275 reputation · 07 Jan 2020, 10:46 UTC
port myPort : String -> Cmd msg is executed, the value is dropped immediately.Cmd always completes successfully from Elm's perspective.Elm treats outgoing ports as fire-and-forget asynchronous boundaries. The compiled JavaScript roughly implements:
app.ports.myPort = { subscribers: [], send: function(value) { this.subscribers.forEach(fn => fn(value)); } }
When subscribers is empty, the forEach loop simply does nothing—no error, no queue, no retry. This is intentional: Elm avoids coupling the Elm runtime to host-side lifecycle.
Have JavaScript signal readiness through an incoming port before Elm sends any outgoing messages.
-- Elm
port outgoing : String -> Cmd msg
port ready : (() -> msg) -> Sub msg
init = (Model [], Cmd.none)
subscriptions model = ready Ready
update msg model =
case msg of
Ready -> (model, outgoing "hello")
_ -> (model, Cmd.none)
// JavaScript
const app = Elm.Main.init({ node: document.getElementById('app') });
app.ports.outgoing.subscribe(console.log);
app.ports.ready.send(null); // Tell Elm we're listening
If you cannot control initialization order, accumulate messages in a List String and flush when the ready signal arrives.
Write a flag from JavaScript on subscribe; read it from Elm via a one-time incoming port or flags at startup. Less reliable across page reloads.
elm make src/Main.elm --output=elm.js.app.ports.myPort.subscribe.init or update.app.ports.myPort.subscribe(msg => console.log('received', msg)) before Elm.Main.init; verify messages arrive.If you are using a framework (Electron, Tauri, Capacitor, etc.) that injects its own port wiring, confirm whether it auto-subscribes before your Elm code runs. In that case, the handshake may be unnecessary—but only if the framework guarantees subscription before init completes.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.