phoenix

Phoenix Channels JavaScript client

Socket Connection

A single connection is established to the server and channels are multiplexed over the connection. Connect to the server using the Socket class:

The Socket constructor takes the mount point of the socket, the authentication params, as well as options that can be found in the Socket docs, such as configuring the LongPoll transport, and heartbeat.

Channels

Channels are isolated, concurrent processes on the server that subscribe to topics and broker events between the client and server. To join a channel, you must provide the topic, and channel params for authorization. Here's an example chat room example where "new_msg" events are listened for, messages are pushed to the server, and the channel is joined with ok/error/timeout matches:

Joining

Creating a channel with socket.channel(topic, params), binds the params to channel.params, which are sent up on channel.join(). Subsequent rejoins will send up the modified params for updating authorization params, or passing up last_message_id information. Successful joins receive an "ok" status, while unsuccessful joins receive "error".

With the default serializers and WebSocket transport, JSON text frames are used for pushing a JSON object literal. If an ArrayBuffer instance is provided, binary encoding will be used and the message will be sent with the binary opcode.

Note: binary messages are only supported on the WebSocket transport.

Duplicate Join Subscriptions

While the client may join any number of topics on any number of channels, the client may only hold a single subscription for each unique topic at any given time. When attempting to create a duplicate subscription, the server will close the existing channel, log a warning, and spawn a new channel for the topic. The client will have their channel.onClose callbacks fired for the existing channel, and the new channel join will have its receive hooks processed as normal.

Pushing Messages

From the previous example, we can see that pushing messages to the server can be done with channel.push(eventName, payload) and we can optionally receive responses from the push. Additionally, we can use receive("timeout", callback) to abort waiting for our other receive hooks and take action after some period of waiting. The default timeout is 10000ms.

Socket Hooks

Lifecycle events of the multiplexed connection can be hooked into via socket.onError() and socket.onClose() events, ie:

Channel Hooks

For each joined channel, you can bind to onError and onClose events to monitor the channel lifecycle, ie:

onError hooks

onError hooks are invoked if the socket connection drops, or the channel crashes on the server. In either case, a channel rejoin is attempted automatically in an exponential backoff manner.

onClose hooks

onClose hooks are invoked only in two cases. 1) the channel explicitly closed on the server, or 2). The client explicitly closed, by calling channel.leave()

Presence

The Presence object provides features for syncing presence information from the server with the client and handling presences joining and leaving.

Syncing state from the server

To sync presence state from the server, first instantiate an object and pass your channel in to track lifecycle events:

Next, use the presence.onSync callback to react to state changes from the server. For example, to render the list of users every time the list changes, you could write:

Listing Presences

presence.list is used to return a list of presence information based on the local state of metadata. By default, all presence metadata is returned, but a listBy function can be supplied to allow the client to select which metadata to use for a given presence. For example, you may have a user online from different devices with a metadata status of "online", but they have set themselves to "away" on another device. In this case, the app may choose to use the "away" status for what appears on the UI. The example below defines a listBy function which prioritizes the first metadata which was registered for each user. This could be the first tab they opened, or the first device they came online from:

Handling individual presence join and leave events

The presence.onJoin and presence.onLeave callbacks can be used to react to individual presences joining and leaving the app. For example:

phoenix

Channel

new Channel(topic: string, params: (Object | function), socket: Socket)
Parameters
topic (string)
params ((Object | function))
socket (Socket)
Instance Members
join(timeout)
onClose(callback)
onError(callback)
on(event, callback)
off(event, ref)
push(event, payload, timeout = this.timeout)
leave(timeout)
onMessage(_event, payload, _ref, event, ref)

Push

Initializes the Push

new Push(channel: Channel, event: string, payload: Object, timeout: number)
Parameters
channel (Channel) The Channel
event (string) The event, for example "phx_join"
payload (Object) The payload, for example {user_id: 123}
timeout (number) The push timeout in milliseconds
Instance Members
resend(timeout)
send()
receive(status, callback)

Timer

Creates a timer that accepts a timerCalc function to perform calculated timeout retries, such as exponential backoff.

new Timer(callback: Function, timerCalc: Function)
Parameters
callback (Function)
timerCalc (Function)
Example
let reconnectTimer = new Timer(() => this.connect(), function(tries){
  return [1000, 5000, 10000][tries - 1] || 10000
})
reconnectTimer.scheduleTimeout() // fires after 1000
reconnectTimer.scheduleTimeout() // fires after 5000
reconnectTimer.reset()
reconnectTimer.scheduleTimeout() // fires after 1000
Instance Members
scheduleTimeout()

Presence

Initializes the Presence

new Presence(channel: Channel, opts: Object)
Parameters
channel (Channel) The Channel
opts (Object = {}) The options, for example {events: {state: "state", diff: "diff"}}
Static Members
syncState(currentState, newState, onJoin, onLeave)
syncDiff(state, diff, onJoin, onLeave)
list(presences, chooser)

Socket

Initializes the Socket *

For IE8 support use an ES5-shim (https://github.com/es-shims/es5-shim)

new Socket(endPoint: string, opts: Object?)
Parameters
endPoint (string) The string WebSocket endpoint, ie, "ws://example.com/socket" , "wss://example.com" "/socket" (inherited host & protocol)
opts (Object? = {}) Optional configuration
Name Description
opts.transport Function? The Websocket Transport, for example WebSocket or Phoenix.LongPoll.

Defaults to WebSocket with automatic LongPoll fallback if WebSocket is not defined. To fallback to LongPoll when WebSocket attempts fail, use longPollFallbackMs: 2500.

opts.longPollFallbackMs Function? The millisecond time to attempt the primary transport before falling back to the LongPoll transport. Disabled by default.
opts.debug Function? When true, enables debug logging. Default false.
opts.encode Function? The function to encode outgoing messages.

Defaults to JSON encoder.

opts.decode Function? The function to decode incoming messages.

Defaults to JSON:

opts.timeout number? The default timeout in milliseconds to trigger push timeouts.

Defaults DEFAULT_TIMEOUT

opts.heartbeatIntervalMs number? The millisec interval to send a heartbeat message
opts.reconnectAfterMs number? The optional function that returns the millisec socket reconnect interval.

Defaults to stepped backoff of:

opts.rejoinAfterMs number? The optional function that returns the millisec rejoin interval for individual channels.
opts.logger Function? The optional function for specialized logging, ie:
opts.longpollerTimeout number? The maximum timeout of a long poll AJAX request.

Defaults to 20s (double the server long poll timer).

opts.params (Object | function)? The optional params to pass when connecting
opts.binaryType string? The binary type to use for binary WebSocket frames.

Defaults to "arraybuffer"

opts.vsn vsn? The serializer's protocol version to send on connect.

Defaults to DEFAULT_VSN.

opts.sessionStorage Object? An optional Storage compatible object Phoenix uses sessionStorage for longpoll fallback history. Overriding the store is useful when Phoenix won't have access to sessionStorage . For example, This could happen if a site loads a cross-domain channel in an iframe. Example usage:
class InMemoryStorage {
  constructor() { this.storage = {} }
  getItem(keyName) { return this.storage[keyName] || null }
  removeItem(keyName) { delete this.storage[keyName] }
  setItem(keyName, keyValue) { this.storage[keyName] = keyValue }
}
Instance Members
getLongPollTransport()
replaceTransport(newTransport)
protocol()
endPointURL()
disconnect(callback, code, reason)
connect(params)
log(kind, msg, data)
hasLogger()
onOpen(callback)
onClose(callback)
onError(callback)
onMessage(callback)
ping(callback)
connectionState()
isConnected()
off(refs, null-null)
channel(topic, chanParams)
push(data)
makeRef()