Skip to content
flowersinthesand edited this page May 24, 2012 · 63 revisions

jQuery.socket is the feature-rich and flexible interface for two-way communication, just as if jQuery.ajax is the interface for Ajax interaction.

jQuery.socket

  • jQuery.socket()

Returns the first socket

  • jQuery.socket(url, [options])

Returns the socket object which is mapped to the given url, or if there is no mapped socket, creates a new socket with the given options, connects to the given url and returns it.

Options

  • transports

An array of the transport ids, in order of index. The transport is used to establish a connection, send data and close the connection. The default is ["ws", "sse", "stream", "longpoll"] and means WebSocket, Server-Sent Events, XDomainRequest streaming, Hidden Iframe streaming, XMLHttpRequest streaming, AJAX long polling, XDomainRequest long polling and JSONP long polling.

  • timeout

A timeout value in milliseconds. The timeout timer starts at the time the connecting event is fired. If the timer expires before the connection is established, the close event is fired. The default is false, which means no timeout.

  • heartbeat

A heartbeat interval value in milliseconds. A opened socket continuously sends a heartbeat event to the server each time the value has elapsed. Actually, the socket sends the event 5 seconds before the heartbeat timer expires to wait the server's echo. If the event echoes back within 5 seconds, the socket reset the timer. Otherwise, the close event is fired. For that reason, the value must be larger than 5000 and the recommended value is 20000. The default is false, which means no heartbeat.

  • lastEventId

A initial value for the last event id to be passed to the url function. The default is empty string.

  • reconnect(lastDelay, attempts)

A function to be used to schedule reconnection. The function is called every time after the close event is fired and should return a delay in milliseconds or false not to reconnect. The function receives two arguments: The last delay in milliseconds used or null at first and the total number of reconnection attempts. This can be disabled by setting the value to false. The default function returns 500 at first and then the double of the last delay of each call.

  • id()

A function to be used to generate a socket id. The function should return a string and the returned string should be unique enough for the server to use it as a identifier of the connection until the connection disconnects. The default function generates a random UUID.

  • url(url, params)

A function to be used to build a url to which to connect. The function should return a url including the given parameters. The function accepts two arguments: The given url and an params object containing socket information. The params has four properties: id, heartbeat, transport and lastEventId. The default function appends a query string representation of the params and a query string parameter _ which is set to the current timestamp to prevent caching to the url as part of a query string.

  • inbound(data)

A function to be used to convert data sent by the server into an event object. Every data sent by the server except binary invokes the function and it should return an event object having type. Binary data is considered as a message event instead. The event object can have the following optional properties: id(an event id), reply(if true then a reply event will be sent) and data(the first argument of corresponding handlers). The default function parses the data as JSON and returns the parsed value because the server sends a JSON string representing the event as data by default.

  • outbound(event)

A function to be used to convert an event object into data to be sent to the server. Every data to be sent to the server except binary invokes the function and it should return a string. Binary data is sent as it is instead. The given event object has id(an event id), type(a event type which the user input), reply(if true then a reply event will be received), socket(a socket id) and data(data which the user input) properties. The default function serializes the event object into JSON and returns it because the server accepts a JSON string representing the event as data by default.

  • xdrURL(url)

A function that can be used to modify a url to be used by the XDomainRequest. For security reasons, the XDomainRequest excludes cookies when sending a request, so a session state cannot be maintained. This problem can be solved by rewriting the url to contain session information. How to rewrite the url is depending on the server app. For details, see my Q&A on StackOverflow. If you wish to disable transports using XDomainRequest, which are streamxdr and longpollxdr, set the value to false. The default function modifies the url only if JSESSIONID or PHPSESSID cookie exists. For example, If the url is url?key=value and JSESSIONID cookie exists, the url becomes url;jsessionid=${cookie.JSESSIONID}?key=value, and if PHPSESSID cookie exists, the url becomes url?PHPSESSID=${cookie.PHPSESSID}&key=value. Otherwise, it returns false.

  • streamParser(chunk)

A function to parse stream response to find data from chunks. The function is called only if the transport is stream and should return an array of data and the returned array's length varies with each chunk because a single chunk may contain a single data, multiple data or a fragment of a data. The default function parses a chunk according to the event stream format, but deals with the data field only.

  • credentials

If the value is true and the browser supports the Cross-Origin Resource Sharing specification, user credentials such as cookies and HTTP authentication is to be included in a cross-origin connection. The spec requires the server to add some response headers. This option affects the EventSource of sse transport and the XMLHttpRequest of stramxhr and longpollajax transport. The default is false

Methods

  • option(key)

Finds the value of an option from the options merged with the default options and the given options. .option("id") returns the socket id and .option("url") returns the original url.

  • session(key, [value])

Gets or sets the session-scoped value with the specified key. The session scope is reset every time the socket opens.

  • state()

Determines the state of the socket. It can be in one of four states: connecting, opened, closed and waiting.

  • on(event, handler)

Adds a given event handler for a given event. When the handler executes, the this keyword refers to the socket where the event occurred.

  • off(event, handler)

Removes a given event handler for a given event.

  • one(event, handler)

Adds a given one time event handler for a given event. A handler bound by one can be called only once in a socket life cycle. In other words, the handler will not be reset upon reconnection.

  • send([event], data, [callback])

Sends an event whose type is a given event or message if not provided and data is a given data to the server. If the socket's state is not opened, the event will be sent when the open event is fired. If a callback is provided, the server will send a reply event as reply and the callback will be invoked with the reply's data.

  • close()

Closes the socket.

  • ns(name)

Returns the namespaced socket whose namespace is the given name, or if it does not exist, creates a new one. The namespaced socket is a logical socket which does not establish a new connection, communicates with the root socket whose the ns method is called and provides a way to multiplex a single connection.

  • connecting(handler), open(handler), message(handler), close(handler), and waiting(handler)

A shortcut for on(event, handler) method.

Events

From the semantic point of view, the unit of data to be sent and be received is the event, like the interaction between user and browser. The socket object's events can be classified like the following.

Pseudo event: They only exist in the client and have nothing to do with the server.

  • connecting()

Fired once when a connection is tried. The socket's state becomes connecting.

  • waiting(delay, attempts)

Fired once when a reconnection has scheduled. The socket's state becomes waiting. The delay in milliseconds and the total number of reconnection attempts are passed to event handlers.

Network event: They are fired in process of connecting and disconnecting by the transport object.

  • open()

Fired once when a connection is established and communication is possible. The socket's state becomes opened and the connecting event becomes disabled.

  • close(reason)

Fired once when a connection has been closed. The socket's state becomes closed and the connecting, open, message and all the custom events become disabled. The connection close reason is passed to event handlers. It can have the following values: notransport(no available transport), done(closed normally), aborted(closed by the user), timeout(timed out) and error(closed due to a server error or could not be opened).

Message event: Effectively, they are sent and received via the connection. The socket object uses several custom events to support additional functions. Such reserved custom events cannot be used artificially.

  • message(data, [callback])

Fired multiple times when a message event has been received from the server. The data sent by the server and the callback for replying to the server are passed to event handlers. That callback is provided only if the event's reply property is true and receives a result of event handling to be sent to the server. The custom event is actually the custom message event, so it can be fired multiple times and receives data and callback as argument in the same way as the message event.

  • heartbeat()

Fired multiple times when a heartbeat event has been echoed back from the server.

  • reply(info)

Fired multiple times when a reply event has been received from the server. The reply information is passed to event handlers and has two properties: id of the original event which requested reply and data which is reply of the server.

Transports

  • ws: WebSocket

Works if the browser supports WebSocket or MozWebSocket. After the open, message, close and all the custom event, it's possible to access a used WebSocket's original event by calling .session('event').

  • sse: Server-Sent Events

Works if the browser supports EventSource and the given url is from the same-origin or from the cross-origin and the EventSource supports CORS. After the open, message, close whose the reason is done and all the custom event, it's possible to access a used Event Source's original event by calling .session('event'). By reason of the Server-Sent Events spec's ambiguity, there is no way to determine whether a connection closed normally or not so that the close event's reason will be done even though the connection closed due to an error.

  • stream: Streaming

Means the streamxdr, streamiframe and streamxhr.

  • streamxdr: XDomainRequest streaming

Works if the browser supports XDomainRequest and the .options.xdrURL(url) returns a appropriate url.

  • streamiframe: Hidden Iframe streaming

Works if the browser supports ActiveXObject and the given url is from the same-origin. This transport differs from the traditional Hidden Iframe in terms of fetching a response text. The traditional transport expects script tags, whereas this transport periodically polls the response text.

  • streamxhr: XMLHttpRequest streaming

Works if the browser supports XMLHttpRequest, dosen't support XDomainRequest and ActiveXObject, and the XMLHttpRequest supports CORS if the given url is from the cross-origin. In the case of Opera, the transport periodically polls the response text.

  • longpoll: Long polling

Means the longpollajax, longpollxdr and longpolljsonp.

  • longpollajax: AJAX long polling

Works if the browser supports XMLHttpRequest or ActiveXObject("Microsoft.XMLHTTP") and CORS if the given url is from the cross-origin.

  • longpollxdr: XDomainRequest long polling

Works if the browser supports XDomainRequest and the .options.xdrURL(url) returns a appropriate url.

  • longpolljsonp: JSONP long polling

Works without qualification.

Examples

  • Simple usage of the socket
$.socket("/socket").message(function(data) {
    $("#data").text(data);
});
  • Specifying transports to be used.
$.socket("/event", {transports: ["sse", "stream"]});
  • Scheduling the reconnection.
$.socket("/event", {
    reconnect: function(lastDelay, attempts) {
        return attempts > 10 ? false : 2 * (lastDelay || 250);
    }
});
  • The inbound and outbound handler for the server which sends and receives a JSON representing data only, not event.
$.socket("/event", {
    inbound: function(data) {
        return {type: "message", data: $.parseJSON(data)};
    },
    outbound: function(event) {
        return $.stringifyJSON(event.data);
    }
});
  • Logging all the inbound and outbound packet.
$.socket.defaults._inbound = $.socket.defaults.inbound;
$.socket.defaults.inbound = function(data) {
    console.log("in\t" + data);
    return $.socket.defaults._inbound.apply(this, arguments);
};
$.socket.defaults._outbound = $.socket.defaults.outbound;
$.socket.defaults.outbound = function(event) {
    var result = $.socket.defaults._outbound.apply(this, arguments);
    console.log("out\t" + result);
    return result;
};

$.socket("/event");
  • Enabling the streamxdr and the longpollxdr transports safely in cases where the server app is built on the Java Servlet API.
$.socket("/event", {
     xdrURL: function(url) {
          var match = /(?:^|;\s*)JSESSIONID=([^;]*)/.exec(document.cookie);
          return match ? url.replace(/;jsessionid=[^\?]*|(\?)|$/, ";jsessionid=" + match[1] + "$1") : url;
     }
});
  • Parsing stream response containing data separated by ';'.
$.socket("/event", {
    streamParser: function(chunk) {
        var data = chunk.split(";");
        
        data[0] = (this.session("data") || "") + data[0];
        this.session("data", data[data.length - 1]);
        
        return data.slice(0, data.length - 1);
    }
});
  • Setting default values.
$.socket.defaults.timeout = 5000;
$.socket.defaults.heartbeat = 20000;
  • Finding the url and the id of the socket.
var clientSideId = $.socket().option("url"), serverSideId = $.socket().option("id");
  • Getting the current state of the connection.
$.socket("test").connecting(function() {
    alert(this.state()); // connecting
})
.open(function() {
    alert(this.state()); // opened
})
.close(function() {
    alert(this.state()); // closed
})
.waiting(function() {
    alert(this.state()); // waiting
});
  • Subscribing custom events.
$.socket().on("mail", function(model) {
    $("#mail-tmpl").tmpl(model).appendTo("#mail-list");
})
.on("chat", function(model) {
    $("#chat-tmpl").tmpl(model).appendTo("#chat-list");
});
  • Replying to the event sent by the server.
$.socket().on("window.size", function(data, callback) {
    callback({width: $(window).width(), height: $(window).height()});
});
  • Acknowledgement of receipt.
$.socket().send({to: id, message: message}, function() {
    alert("@" + id + " has just read your message");
});
  • Performing an asynchronous request like Ajax without using XMLHttpRequest if the used transport is WebSocket.
$.socket().send("account.unique", username, function(unique) {
    alert("This username is " + (unique ? "available" : "already taken"));
});
  • Retrieving all the data needed to display utilizing a single connection.
$.socket().send("init", location.href, function(data) {
    init(data);
});
  • Closing the socket.
$.socket().close();
  • Multiplexing a single connection using namespace.
$.socket().ns("chat").open(function() {
    this.send("Hi, there?");
});
$.socket().ns("dm").message(function(msg) {
     alert("@" + msg.from + ": " + msg.content);
});
  • Chat socket.
$(function() {
    var username, 
        lastUsername,
        content = $("#content")[0];
    
    function notify(text) {
        $('<p class="message notice"/>').text(text).appendTo(content);
        content.scrollTop = content.scrollHeight;
    }
    
    $("#editor input").keyup(function(event) {
        var self = this;
        
        if (event.which === 13 && $.trim(self.value)) {
            if (!username) {
                username = self.value;
                $("#editor p").addClass("user").removeClass("guide").text(username);

                $.socket("chat")
                .connecting(function() {
                    notify("The connection has been tried");
                })
                .open(function() {
                    notify("The connection has been opened");
                    $(self).removeAttr("disabled").focus();
                })
                .close(function(reason) {
                    notify("The connection has been closed due to '" + reason + "'");
                    $(self).attr("disabled", "disabled");
                })
                .message(function(data) {
                    if (lastUsername !== data.username) {
                        lastUsername = data.username;
                        $('<p class="user"/>').text(data.username).appendTo(content);
                    }
                    
                    $('<p class="message"/>').text(data.message).appendTo(content);
                    content.scrollTop = content.scrollHeight;
                })
                .waiting(function(delay, attempts) {
                    notify("The socket will try to reconnect after " + delay + " ms");
                    notify("The total number of reconnection attempts is " + attempts);
                });
            } else {
                $.socket().send({username: username, message: self.value});
            }
            
            self.value = "";
        }
    })
    .focus();
});

Clone this wiki locally