1.5.9
Phoenix Channels JavaScript client
A single connection is established to the server and
channels are multiplexed over the connection.
Connect to the server using the Socket
class:
let socket = new Socket("/socket", {params: {userToken: "123"}})
socket.connect()
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 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:
let channel = socket.channel("room:123", {token: roomToken})
channel.on("new_msg", msg => console.log("Got message", msg) )
$input.onEnter( e => {
channel.push("new_msg", {body: e.target.val}, 10000)
.receive("ok", (msg) => console.log("created message", msg) )
.receive("error", (reasons) => console.log("create failed", reasons) )
.receive("timeout", () => console.log("Networking issue...") )
})
channel.join()
.receive("ok", ({messages}) => console.log("catching up", messages) )
.receive("error", ({reason}) => console.log("failed join", reason) )
.receive("timeout", () => console.log("Networking issue. Still waiting..."))
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.
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.
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.
Lifecycle events of the multiplexed connection can be hooked into via
socket.onError()
and socket.onClose()
events, ie:
socket.onError( () => console.log("there was an error with the connection!") )
socket.onClose( () => console.log("the connection dropped") )
For each joined channel, you can bind to onError
and onClose
events
to monitor the channel lifecycle, ie:
channel.onError( () => console.log("there was an error!") )
channel.onClose( () => console.log("the channel has gone away gracefully") )
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 are invoked only in two cases. 1) the channel explicitly
closed on the server, or 2). The client explicitly closed, by calling
channel.leave()
The Presence
object provides features for syncing presence information
from the server with the client and handling presences joining and leaving.
To sync presence state from the server, first instantiate an object and pass your channel in to track lifecycle events:
let channel = socket.channel("some:topic")
let presence = new Presence(channel)
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:
presence.onSync(() => {
myRenderUsersFunction(presence.list())
})
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:
let listBy = (id, {metas: [first, ...rest]}) => {
first.count = rest.length + 1 // count of this user's presences
first.id = id
return first
}
let onlineUsers = presence.list(listBy)
The presence.onJoin
and presence.onLeave
callbacks can be used to
react to individual presences joining and leaving the app. For example:
let presence = new Presence(channel)
// detect if user has joined for the 1st time or from another tab/device
presence.onJoin((id, current, newPres) => {
if(!current){
console.log("user has entered for the first time", newPres)
} else {
console.log("user additional presence", newPres)
}
})
// detect if user has left from all tabs/devices, or is still present
presence.onLeave((id, current, leftPres) => {
if(current.metas.length === 0){
console.log("user has left from all devices", leftPres)
} else {
console.log("user left from a device", leftPres)
}
})
// receive presence data from server
presence.onSync(() => {
displayUsers(presence.list())
})
Initializes the Push
Subscribes on channel events
Subscription returns a ref counter, which can be used later to unsubscribe the exact event listener
integer
:
ref
const ref1 = channel.on("event", do_stuff)
const ref2 = channel.on("event", do_other_stuff)
channel.off("event", ref1)
// Since unsubscription, do_stuff won't fire,
// while do_other_stuff will keep firing on the "event"
Unsubscribes off of channel events
Use the ref returned from a channel.on() to unsubscribe one handler, or pass nothing for the ref to unsubscribe all handlers for the given event.
(string)
(integer)
// Unsubscribe the do_stuff handler
const ref1 = channel.on("event", do_stuff)
channel.off("event", ref1)
// Unsubscribe all handlers from event
channel.off("event")
Sends a message event
to phoenix with the payload payload
.
Phoenix receives this in the handle_in(event, payload, socket)
function. if phoenix replies or it times out (default 10000ms),
then optionally the reply can be received.
Push
:
channel.push("event")
.receive("ok", payload => console.log("phoenix replied:", payload))
.receive("error", err => console.log("phoenix errored", err))
.receive("timeout", () => console.log("timed out pushing"))
Leaves the channel
Unsubscribes from server events, and instructs channel to terminate on server
Triggers onClose() hooks
To receive leave acknowledgements, use the receive
hook to bind to the server ack, ie:
(integer
= this.timeout
)
Push
:
channel.leave().receive("ok", () => alert("left!") )
Initializes the Socket
For IE8 support use an ES5-shim (https://github.com/es-shims/es5-shim)
(string)
The string WebSocket endpoint, ie,
"ws://example.com/socket"
,
"wss://example.com"
"/socket"
(inherited host & protocol)
(Object?
= {}
)
Optional configuration
Name | Description |
---|---|
opts.transport string?
|
The Websocket Transport, for example WebSocket or Phoenix.LongPoll.
Defaults to WebSocket with automatic LongPoll fallback. |
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: (payload, callback) => callback(JSON.parse(payload))
|
opts.timeout number?
|
The default timeout in milliseconds to trigger push timeouts.
Defaults |
opts.heartbeatIntervalMs number?
|
The millisec interval to send a heartbeat message |
opts.reconnectAfterMs number?
|
The optional function that returns the millsec
socket reconnect interval.
Defaults to stepped backoff of: function(tries){
return [10, 50, 100, 150, 200, 250, 500, 1000, 2000][tries - 1] || 5000
}
|
opts.rejoinAfterMs number?
|
The optional function that returns the millsec
rejoin interval for individual channels.
function(tries){
return [1000, 2000, 5000][tries - 1] || 10000
}
|
opts.logger Function?
|
The optional function for specialized logging, ie:
function(kind, msg, data) {
console.log(`${kind}: ${msg}`, data)
}
|
opts.longpollerTimeout number?
|
The maximum timeout of a long poll AJAX request.
Defaults to 20s (double the server long poll timer). |
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. |
Disconnects the socket
See https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent#Status_codes for valid status codes.
Returns true if a logger has been set on this socket.
Removes onOpen
, onClose
, onError,
and onMessage
registrations.
(any)
(refs)
list of refs returned by calls to
onOpen
,
onClose
,
onError,
and
onMessage
Initializes the Presence
Used to sync the list of presences on the server
with the client's state. An optional onJoin
and onLeave
callback can
be provided to react to changes in the client's local presences across
disconnects and reconnects with the server.
(any)
(any)
(any)
(any)
Presence
:
Used to sync a diff of presence join and leave
events from the server, as they happen. Like syncState
, syncDiff
accepts optional onJoin
and onLeave
callbacks to react to a user
joining or leaving from a device.
(any)
(Object)
Name | Description |
---|---|
$1.joins any
|
|
$1.leaves any
|
(any)
(any)
Presence
:
Returns the array of presences, with selected metadata.
Presence
:
Creates a timer that accepts a timerCalc
function to perform
calculated timeout retries, such as exponential backoff.
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
Cancels any previous scheduleTimeout and schedules callback