Thursday, March 6, 2014

Microsoft 70-480: Implement a callback (WebSockets)

Exam Objectives


Receive messages from the HTML5 WebSocket API; use jQuery to make an AJAX call; wire up an event; implement a callback by using anonymous functions; handle the “this” pointer


Quick Overview of Training Materials


Programming in HTML5 with JavaScript and CSS3 - Training Guide - Chapters 3, 6, 8, 9, 10
MSDN - The WebSocket API
About HTML5 WebSockets - Websocket.org
MSDN Articles on HTML5 - Specifically  WebSockets: Stable and Ready for Developers
The WebSockets API from w3.org
Fully Understanding the this Keyword
Simple server implemtation in C# EchoHandler.ashx.cs ... probably outside the scope of this topic through



WebSockets


I'm going to go out on a limb and say that this test is probably only interested in the JavaScript, client side implementation side of WebSockets; server-side implementation of WebSockets is probably covered by exam 70-486.  That being said, I included a couple links to some demos if the server side is of interest.  WebSockets is deceptively easy to understand on the client side, but is actually a very sophisticated and powerful technology. The training guide offers rudamentary coverage of WebSockets, for a more complete understanding I would recommend perusing all the above links and watching the first Channel 9 video.

WebSockets is a communication technology that allows for efficient real-time full duplex (two way) communication between the browser and the server.  Because HTTP is a request-respond type of protocol, there is not an elegant way to implement a "push" type of communication model where the server sends the browser updates.  Workarounds such as periodic and, in particular, long polling have been used, but because each HTTP request and response includes a number of headers, bandwidth usage is inefficient, and because updates must be constantly requested through the poll, latency can become a much more noticable problem.  WebSockets addresses these shortcomings of polling.

Communicating with WebSockets begins with a handshake.  An HTML GET request is sent the server requesting an "upgrade" to a different protocol: WebSockets.  If the server accepts this request it will send back an HTTP response of 101 (switching protocols).  WebSockets will then use the same TCP socket utilized by the handshake to communicate. WebSocket frames are then exchanged in real time over this connection.  WebSockets can use either unencrypted TCP on port 80, or encrypted SSL over port 443.  Because WebSockets uses the same default ports as HTTP and HTTPS, it has no problem with proxies.  Using a secure connection actually can increase performance as proxies will not try to interpret the WebSockets frames if they are encrypted.

On the client side, WebSockets is implemented through the use of the WebSocket object. The above handshake is automatically undertaken when a new WebSocket object is created.  The constructor for a WebSocket object takes a URL as a parameter, which should point to the server side of the application. A typical call might look like:

newWS = new WebSocket('ws://echo.websocket.org/');

When the HTTP handshake is complete, the readyState of the new WebSocket object is changed to OPEN. There are four enumerated values that readyState can hold:
  • CONNECTING (numeric value 0) The connection has not yet been established.
  • OPEN (numeric value 1) The WebSocket connection is established and communication is possible.
  • CLOSING (numeric value 2) The connection is going through the closing handshake, or the close() method has been invoked.
  • CLOSED (numeric value 3) The connection has been closed or could not be opened.
Opening the connection also fires the "open" event. Events are also fired if the connection is closed, if a message is received, or if there is an error. These can be addressed by assigning functions to the .onopen, .onclose, .onmessage, and .onerror properties on the WebSockets object.  This should be done immediately following the creation of the object to avoid missing any triggered events:

newWS = new WebSocket('ws://echo.websocket.org/');
newWS.onopen = function (e) {onOpen(e)};
newWS.onclose = function (e) {onClose(e)};
newWS.onmessage = function (e) {onMessage(e)};
newWS.onerror = function (e) {onError(e)};

Now that a WebSockets connection has been made, it is possible to send and receive messages.  WebSockets allows messages to be in UTF-8 (text), a binary blob, or an arrayBuffer. The client sends messages to the server by using the .send() method. If we were sending a "hello world" message to the server it would look like this:

newWS.send("Hello World from WebSockets!");

Any messages the client end of the connection receives from the server are handled by the function assigned to the onmessage property.  When we are all done with socketed communication, we can close the WebSockets connection by using the .close() method. This method can include a code ( must be an interger equal to 1000 OR in the range 3000-4999) and a string of text giving the reason the connection was closed. A normal close may look like this:

newWS.close( 1000, "Closed by user.");  

The echo server test is the demo commonly encountered.  The training guide includes one, as does the MSDN article WebSockets: Stable and Ready for Developers, though the MSDN article also demostrates binary data. While not substantially different from text data (WebSockets treats both the same really), it does make for a slightly more interesting demo. I put together a JSFiddle demo as well, really just using existing demo code from websockets.org and the training guide:


The training guide does also make an interesting point about preventing timeouts.  The books suggestion is to use setTimeout to periodically send an empty message to keep the connection alive.  The book also points out that disconnects caused by network problems may require the application to use some kind of identifier when communicating to ensure that when a client reopens the connection the server recognizes that it is dealing with an existing client.


Ajax with JQuery



Traditional Ajax calls with JavaScript use the XMLHTTPRequest object to make calls back to the server in order to load bits of information into the DOM without reloading the page. Data requested with AJAX must be from the same origin, i.e. the domain, subdomain, port, and protocol of the requested resource must match that of the requesting URL.   A typical JavaScript Ajax call would look something like this:

xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
  {
  if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
    // Do something with xmlhttp.responseText
    }
  }
xmlhttp.open("GET","ajax_info.txt",true);
xmlhttp.send();

JQuery simplifies Ajax with a number of methods. jQuery.ajax() is the base method for doing Ajax in jQuery, with additional methods that act as shorthand for .ajax(). These methods follow: (demos are all from w3schools.com)
jQuery.get() is equivalent to:

$.ajax({
   url: url,
   data: data,
   success: success,
   dataType: dataType
});

where url is the requested resource, data is information sent along to the requested URL, success is a callback function that is called when the request is successful, and dataType is the type of data expected from the server (xml, json, script, or html).

jQuery.post() is nearly identical to .get() with one exception:

$.ajax({
   type: "POST",
   url: url,
   data: data,
   success: success,
   dataType: dataType
});

The type field indicatates that this request is a POST. Because pages retrieved with POST are never cached, the cache and ifModified options is .ajaxSetup() have no effect on .post().

The jQuery.getJSON() and jQuery.getScript() calls are also nearly identical to the .get() method, varying primarily in thta the dataType field is set to the appropriate type.  jQuery.getJSON() is shorthand for:

$.ajax({
   url: url,
   data: data,
   success: success,
   dataType: "json"
});

jQuery.getScript() is shorthand for the following. Notice it does not include a "data" field. When the call is successful it runs the returned script:


$.ajax({
   url: url,
   success: success,
   dataType: "script"
});

jQuery.load() is essentially the same as .get(), except that is a method executed on a collection of elements rather than a global function. The data returned via Ajax is automatically loaded into each element in the collection, which contrasts with the other shorthand functions which call a success callback function that may or may not load the returned data into an element.  It is possible to pass a callback function to .load() that fires after the success callback function is complete. The  .load() function is essentially shorthand for:

$.ajax({
   url: url,
   data: data,
   success: function () {this.html( data );},
   complete: complete
});

Finally, the base jQuery.ajax() function is highly configurable, and is the fallback option if more fine control of functionality is required than can be had through the use of the shorthand methods.  The function can take any number of the following parameters as arguments in JSON format (as above):



Setting
Type
Default
Description
accepts
PlainObject
depends on DataType
The content type sent in the request header that tells the server what kind of response it will accept in return.
async
Boolean
true
Asynchronous calls will not halt execution while waiting for the response.
beforeSend
Function
-
A pre-request callback function that can be used to modify the jqXHR object before it is sent
cache
Boolean
true (except for dataType ‘script’ and ‘jsonp’
If set to false, it will force requested pages not to be cached by the browser (in most cases).
complete
Function
-
A function to be called when the request finishes (after success and error callbacks are executed).
contents
PlainObject
-
An object of string/regular-expression pairs that determine how to parse the response, given its content type.
contentType
String
application/x-www-form-urlencoded; charset=UTF-8
The W3C XMLHttpRequest specification requires UTF-8 charset. Determines the content type sent to the server
context
PlainObject
-
Used to set the context (such as when using “this” keyword)
converters
PlainObject
depends on dataType
An object containing dataType-to-dataType converters
crossDomain
Boolean
false (same domain request), true (cross domain request)
Allows you to force a cross domain request, such as a server side redirect
data
PlainObject or String
-
Data to be sent to the server in the form of key/value pairs. Objects and arrays are serialized. If using GET this string is appended to URL
dataFilter
Function
-
Function that acts on raw XMLHTTPRequest response.
dataType
String
guess (xml, json, script, or html)
The type of data that you're expecting back from the server. If none is specified, jQuery will try to infer it based on the MIME type of the response
error
Function
-
A function that is called if the request fails. Causes include timeout, error, abort, and parsererror.
global
Boolean
true
Whether to trigger global Ajax event handlers for this request.
headers
PlainObject
{ }
Allows the addition of additional HTTP headers.  Headers are added as key/value pairs.
ifModified
Boolean
false
Allow the request to be successful only if the response has changed since the last request.
isLocal
Boolean
depends
Allow the current environment to be recognized as "local," (e.g. the filesystem), even if jQuery does not recognize it as such by default.
jsonp
String
-
Override the callback function name in a jsonp request. This value will be used instead of 'callback' in the 'callback=?' part of the query string in the url.
jsonpCallback
String or Function()
-
Specify the callback function name for a JSONP request. This value will be used instead of the random name automatically generated by jQuery.
mimeType
String
-
Overrides the mime type of the XMLHTTPRequest
password
String
-
Password to be used with HTTP access authentication.
processData
Boolean
true
By default, data passed in to the data option as an object will be processed and transformed into a query string. Too send a DOMDocument, or other non-processed data, set to false.
scriptCharset
String
-
Only applies when the "script" transport is used when the character sets of the local page and the remote script do not match.
statusCode
PlainObject
{ }
An object of numeric HTTP codes and functions to be called when the response has the corresponding code.
success
Function
-
A function to be called if the request succeeds.
timeout
Number
-
Set a timeout (in milliseconds) for the request. This will override any global timeout set with $.ajaxSetup().
traditional
Boolean
-
Set this to true if you wish to use the traditional style of param serialization.
type
String
‘GET’
The type of request to make ("POST" or "GET"). PUT and DELETE can also be used here, but they are not supported by all browsers.
url
String
the current page
The URL to which the request is sent.
username
String
-
Username to be used with HTTP access authentication.
xhr
Function
ActiveXObject(IE) or XMLHttpRequest
Callback for creating the XMLHttpRequest object. Override to provide your own implementation for XMLHttpRequest or enhancements
xhrFields
PlainObject
-
Name/Value pairs to set on the native XHR object. For example, you can use it to set withCredentials to true for cross-domain requests if needed.


Events, callbacks, and 'this'


Because events often invoke callback functions called event handlers, and because these event handlers often make use of the keyword "this", it makes sense to consider these concepts together.  This segues nicely from Ajax since events and callbacks are essential to making Ajax work. Looking at the raw JavaScript implementation of a simple Ajax call, we can identify these components:

// first we create the XHR object
xmlhttp=new XMLHttpRequest();
// here we assign an anonymous function as an event handler that is 
// called any time the "onreadystatechange" event has fired. At this point in the code, the
// readyState is equal to 0 (uninitiallized), meaning it is instantiated but not open
xmlhttp.onreadystatechange=function()
  {
  //readyState == 4 indicates that all data has been receieved
  if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
    // Do something with xmlhttp.responseText
    }
  }
// when we call .open() on the xhr object, the readyState changes to 1 (open), 
// which fires the above event. Because the readyState != 4, the function does nothing
xmlhttp.open("GET","ajax_info.txt",true);
// according to the spec, when we call .send() on the xhr object, the readyState changes to 
// 2 (sent), which fires the above event. However, in Chrome and Firefox this change is not 
// made until the response headers are received.  Because the readyState != 4, the function 
// does nothing
xmlhttp.send();

The browser is not locked up waiting for the response because the request is asynchronous.  When the browser receives the headers for the requested resource, the readyState changes to 3 (receiving). When the data is completely finished downloading, the readyState changes to 4 (complete), at which point the anonymous function assigned to the event listener will actually do something with it (as long as the status also is == 200 (OK).  The following JSFiddle demo shows how the readyState changes flow compared to the JavaScript flow.




Wiring up other events in JavaScript is simply a matter of assigning a callback function to the event. If we want to call a function when the user clicks a button, we can simply say:

<button onclick="alert(this.value)" value="Hello World">Say Hi!</button>

<button onclick="alert(this.value)" value="Goodbye Cruel World">Die...</button>



When the button is clicked, the "onclick" event is fired, which calls the function "alert" with the .value property of the clicked button as a parameter. Notice that even though the callback function is identical, the value changes because "this" determines which value is passed to the callback function.

Functions in JavaScript are easier to understand if you've been exposed to a language like LISP where there is no real distinction between procedures and data. The only real difference between a function and the string of characters representing a function is the fact that the interpreter understands to evaluate a function. Because functions in JavaScript are "first class citizens", they can be passed as arguments to other functions, like any other object.  

 By using callback functions, we are not tied to the traditional program flow.  This JSFiddle example demonstrates this concept using .setTimeout(), which calls a function after a set number of milliseconds have elapsed.  In this case we are using anonymous functions, which look like this:

function () {//do stuff}

For a one off function this can save us some trouble, though we could easily use named functions as well:

function myFun () {//do stuff}
setTimeout(myFun, 1000) // calls myFun after 1 second.




One notable point the recurial article makes regarding callback functions is how call() can be used to set the context of an anonymous function, which allows for the use of the "this" keyword with whatever we pass to call().  As the Understanding this article points out, the value of "this" depends upon the context in which it is called.  Key points about "this":
  • when a function is created, a reference called "this" is create that points to the property or method to which the function belongs.
  • "this" is a keyword, not an argument or parameter, and it cannot be modified (you can modify what it points to, but you can't directly modify where it points), however...
  • you can influence the value of "this" by changing the context in which it exists (storing "this" in a variable called "that", using call() and apply()).
  • if you use the new keyword with a custom constructor, "this" in the constructor refers to the instantiated object. If you don't use new, "this" refers to the context in which the constructor is called.
This JSFiddle demo implements all the examples from the Understanding this article:



No comments:

Post a Comment