What do you want to learn?
Leverged
jhuang@tampa.cgsinc.com
Skip to main content
Pluralsight uses cookies.Learn more about your privacy
HTML5 Advanced Topics
by Craig Shoemaker
Learn to create applications that take advantage of HTML5’s support for offline applications, UI threading, local storage, Web Sockets and Microdata formats
Start CourseBookmarkAdd to Channel
Table of contents
Description
Transcript
Exercise files
Discussion
Learning Check
Recommended
Fundamentals of HTML5 : Offline Applications
Introduction
Hello there, and welcome to Pluralsight's Advanced HTML5. This is Craig Shoemaker, and in this course you have an opportunity to learn about some of the most compelling reasons to create websites using HTML5. Now this module is all about HTML5 Offline Applications and subsequent modules include Geolocation, Web Storage, Web Workers, and WebSockets. And while you'll get an opportunity to see each one of these technologies individually, you'll soon learn how marrying them together can pave the way to building some truly interactive websites, all within HTML5. Now the outline for this module is to define exactly what is an offline application and some ideas about how you might use it. And then we'll take a look at the anatomy of an offline application and also delve into some of the application cache API and lifecycle details. We'll review browser support and then dive into the demos. I'll show you some of the common events available within offline apps, how you can do manual and automatic updates, as well as building a journal application that doesn't care whether it's connected to the web or not. And finally, I'll review some of the information that you'll need to know when you start debugging one of these applications. So thanks so much for joining me and let's dig into exactly what is an offline application.
What Are HTML5 Offline Applications
The first thing that I'd like discuss with you is what exactly is an offline application. And if you've had experience with building offline applications with say like Silverlight, then you're definitely thinking in the right direction. The architecture that surrounds a typical web application is that you need connectivity to the internet in order for it to work correctly. So the page is served to the user, the user does something, interacts with the page or the site, and it takes these roundtrip requests to and from the server in order to operate the site correctly. Well, when you get in a situation where internet connectivity is lost, that web application ceases to work correctly. So the idea behind offline applications is that instead of operating like a standard web application, an offline application will continue to work even if there's no internet connectivity. And the way that happens is that the files that are needed in order to get certain parts of the application working correctly are copied down onto the user's computer and saved in a place where those files can be reliably retrieved. Now, I say that part of it because obviously with web applications often we need access to services or databases or other parts of the application. And so, the offline apps attempts to take care of as much as it can, but there are certainly exclusions within the architecture of an offline application. The other thing that you want to make sure that you keep in mind when you're dealing with an offline application is that if you setup your website to have certain areas of it as an offline application, or even certain pages of your website to be offline applications, and you can absolutely do that, when those pages are accessed by the user, even when they go to say, http somesite.com/yourpage, even when they go to that page and the computer is connected to the web, those files will be served from the application cache. And this can get a little tricky when you get into some debugging and some other areas and so I'll help take you through the different details surrounding that. But in terms of programatically what are offline applications, it's basically the marriage of two pieces of technology, one that's been supported within browsers for quite a while. So the first thing that we want to be able to do is to build our applications that respond to the online and offline browser events. So there are events that are fired when the browser recognizes that it's online or offline from the web, and there's even a Boolean property which you can check to find out whether it is online. On top of that, and this is where the new features of HTML5 are available, is the application cache. And so application cache comes with a series of its own events and its series of own construction in order again, to make that place on the user's computer where pages can be served reliably over and over again. And so the idea is that this is in contrast to regular browser caching where if you disconnect from the web and you try to refresh a normal page, you might get the content for that page, but the images won't show up and CSS often won't show up and you'll have different broken areas. Well application cache gives you the opportunity to again reliably serve up those files even when you're not connected to the web.
Anatomy of an Offline Application
Next I'd like to review the anatomy of an offline application. And to sort of put something in your mind's eye of what we're working toward, this is the journal application that we'll review later on in this module. And the idea is that if you have messages that you want to journal to yourself, you could come into this textbox, type in the messages and press Send, and whether you're connected to the web or whether you're not, if you're not connected to the web those messages are cached and once the connection is reestablished to the internet, the browser then recognizes that the connection is now available and then saves all the items that were sort of saved up in a buffer off to the server. But if you're connected to the web, it just sends it immediately. So that's how this journal application will work. But let me take you through some of the basic building blocks of an offline application. So, this depicts some script and markup that you're probably pretty used to seeing, but there are a few little differences here that I would like to bring to your attention. First of all, that is a manifest file is defined up in the HTML tag. And this right here is basically where you turn a corner from this page being a regular web page or web application and being an offline application or just an offline page. So any one of the HTML files that needs to be available offline must have a value placed inside the manifest attribute of the HTML tag. And within the manifest will list all the files that are needed within the application, but the manifest is the first clue to the browser that something different is going on here. And then we have things that are typical of any HTML page. So we have all the assets. So that's your CSS files, your JavaScript files, assets would include as well images that are on the page, anything that is needed in order to make up this page is what I'll call assets. Now there's no arrow for the application cache, but the application cache is that part of the space that's reserved for information for this application on the user's machine, but that's part of the anatomy of it as well. So we have the pages that are served up as part of the application, but there's that bucket that you have an opportunity to place files into, again that are served reliably whether you're connected to the internet or not and that's the application cache. And then we also have the online awareness status. And like I refer to in some of the previous slides, the browsers have had this ability to know whether or not they're online or not for some time, and that's available through the navigator object. And so you'll see as I use this piece of information within the application, in order to tell the user, in order to respond to the connectivity status and be able to say whether or not the application is online or offline, and also programmatically will respond to any changes by looking at this flag by being able to send out the information that's built up within that array or within that buffer. Now to further delve into the anatomy of an offline application, let's take a look at the central nerve center of an offline app, and that is the cache manifest file. And there's a number of different sections within the manifest file and there's some conventions and some rules that you need to be aware of as well. And so let's take a look at this manifest file piece by piece here. So the first section here is the first line, and that is CACHE MANIFEST. Now, this has to be the first line of your cached manifest file. It can't be a comment, it can't be anything else, it needs to be CACHE MANIFEST. Trust me on that one. The next thing is, as you build an offline application, again, everything is controlled through the manifest file and so if you go to change an HTML file and you save that change to the server and then you go to the application, the running application, and refresh the page, you will not see that change. You could refresh that page from here until the sky turns red and you'll never see the change. And that's because offline applications only recognize changes when there's been an update to the manifest file. And so what you need to do is have some sort of mechanism in order to tell the outside world, hey, these pages have changed. Well, since this is a list of all the page names, you may change a lot within the page, but you never change the page name. So you need again, a mechanism to be able to flag everything and tell the browser to download all the new versions of the files. And so that's why often what you'll see within the tutorials on offline applications and using manifest files is to have some sort of a versioning type of comment scheme somewhere within the file. And so here I've kept it basically very simple. The comments start with the hash symbol and version 1. And so as you make changes to your files, you can change this version number and then refresh the page and it'll go through the whole work of downloading all of the files for your manifest. Now, what you need to know also is that the files that are listed in the manifest are downloaded and the application is, I'm using quotes here, installed on the user's machine in somewhat of a transactional way. So if one of those files fails, you get a 404 on one of the files or something ends up happening, none of the files are used in the application. It's as if none of them were downloaded. So that tells you a couple things. Number one, if you have a problem with a single file, then you'll have problems with the entire application. But number two, on the positive side of things, is that if you get a successful download, you know that you have successfully brought all of the files listed within your application down to the client's machine and you reliably know that they're available. So, this whole mechanism of how the cache manifest file works is built in such a way that you can have reliability knowing that the files that you need and the functionality that you need will be available on the client. The next section is the Cache section. And this is the list of files that you're expecting to be on the client's machine and available through the offline application cache. So I have some .aspx pages here and some JavaScript, and even some images. Again, you can list as many as you want and as many types of files that you want and you just put everything here within the Cache section. The Network section is basically an exclusion list. And these are URLs or pages that you want to make sure are never attempted to be cached because let's say you have a search page or you have some sort of interactivity built within your application that requires a server, maybe you have to have a database, you have to have access to that service. Well, you want to be able to tell your application that you explicitly do not try to cache any of the pages within either this path or on those pages, and so the Network section allows you to do that. And also, you have the ability to create some fallback pages. So for instance if you're working offline and you want to be able to show a different page for your homepage, then you can create the mappings within the fallback section to say that this page falls back over to this other page and that's a space separating the two, not a tab or any other special character. So the fallback section will give you the ability to serve up some content, even if it's different when people are browsing offline. And the final piece of trivia that you must know about the cache manifest file is that the mime type must be served as test/cache-manifest, and the encoding must be UTF-8. And in the demos you'll see how I set this up within an ASP.NET application in order to handle that, but setting mime types are some pretty standard fare on most servers and so you just want to make sure that you have the correct settings within the HTTP header so the browsers understand what to do with the file once they get it.
Caching Types
Now, one of the most critical concepts that you need to have concrete in your mind is the difference between different types of caching. Now, I've referred to a little bit of standard browser caching, which you should be very, very familiar with and the idea is that when you go to a web server and you request a page, that HTML and the images and the CSS and the JavaScript and everything that you need for that page is copied down to your machine. And so when you make subsequent requests while you're online looking at that application save for the same CSS file, rather than the browser having to go and fetch that file from the server again, if it's the same exact file, it just serves what's in the browser cache and can keep on going. So it's this operation of the browser looking at each page and looking at the requests and trying to find the files that it doesn't have in order to display a particular web page and if it doesn't have that information, it'll go to the server and request it. If it does have it, it'll serve it out of the browser cache. And this is a very well established mechanism built into the world wide web. And in fact, the web would probably soon crash without this type of caching because every single page or every single asset or every single file would have to be served over and over and over again to every single client upon request of a single page. And so this again, is a concept that is not changing, but I want you to have a very clear understanding in your mind of how browser caching works. Now, application caching is a little bit different. The concept is somewhat the same except rather than having all of these different files that make up a page or an application, sort of being disparate, it groups them together into an application manifest file. And this is a manifest. It's a laundry list of all the files that are needed in order to make up this application. The distinction here though is the fact that they're grouped together and those files are set aside as being again, I keep coming back to this concept because I want you to understand that they're reliably served from the client. It's not like hitting refresh on your browser when you're normally not connected to the web. You know that these files will be served to you, but the thing that you have to make sure is that you do not mix browser caching with application caching. And the important thing to note here is that if you think about how browser caching works, and that is usually a header is sent across, an HTTP header that tells a certain page, let's just say a page for a moment here, that this page is set to expire in a week, or three days or whatever, and conversely if you have application cache setup, the way this works is that it groups all those files together and the only way a browser can recognize any change for all of the files in the application cache is to have a change within the manifest file. And you'll see this in action when I get into the demos, but consider the scenario to where you make a change on an HTML page, you go and make a change to the manifest file, which is the master list of all the files within an application, but the browser doesn't think that that file is changed, it will then serve it from browser cache instead of the application cache. So I'm bringing this up because as we get into the demos you'll notice that all of my pages are, I happen to be most familiar with ASP.NET and so they're all .aspx pages, but this is not necessary whatsoever. All of the demos and all the code that I show you is completely server agnostic. The only difference is that I needed to format the server in such a way in order to create no cached pages. And the way you know if you have no cached pages is that if you open up something like Fiddler, you can get an opportunity to see the requests that are coming back and you'll notice here that this is a page that's been setup explicitly not to cache within the browser, Cache-Control is set to no-cache, Pragma is set to no-cache, and Expires is -1. This makes sure that the browser does not try to cache that page. And I had to do it on the server because that's the only place you can reliably do it. If you try to do it within Meta tags, and there's lots of code samples on the web that'll show you how to do that, it just won't work because often the browsers are ignoring Meta tags more and more often. So in order to change the HTTP header itself, what you need to be able to do is control that somewhere on the server and I chose to do that basically by using .aspx files. You can configure your server to serve up HTML files this way, but for portability and making it so you can run these samples, the easiest I chose to do it within .aspx pages. So again, no server requirements, but you have to make sure that the caching does not collide when you're using the different types of cache.
Progression of Events
Now before we dive right into the demos, there's a few things that I want to have clear in your mind before we start looking at the code. And the first thing is the progression of events. Now all of this is available through window.applicationCache and that's the object model that's making the application cache available. Now what happens is that when you first load a page that's setup with a a manifest file, is it fires off the checking event. And the checking event will look to see if there's any files in the manifest that need to be downloaded. And so it examines the manifest, it starts downloading the files, and it begins firing progress events and then once all of those files are available, it fires the cached event. Now, if you reload that page and the manifest is not updated, it'll fire the checking event and then it'll say, well nothing's changed within this manifest, so it'll return no update. But, if something changes within one of the pages and then you go and change the manifest, if you hit refresh again what happens is it'll do basically the same thing it did at the beginning. You'll go through the checking event and it'll recognize there's some changes, it'll download them, give you some progress, and then it'll fire the cached event. So you have to go through this process in order to recognize any changes or any new files available within your application. So technically speaking, the cache states that are available are Uncached, Idle, Checking, Downloading, Updateready, and Obsolete. So, Uncached just means that you've never been to this page, the cache is not initialized. Idle means this is the state where everything has been downloaded, the cache hasn't been updated, you're basically just running the page in sort of an idle state. Obviously Checking is when it's looking at the manifest for any changes and downloading would be when it's actually transferring files that are listed within the manifest down to the browser. Updateready, this is the part when you know when all the files are now available and where the update is ready and it's now safe for the user to begin using these new files. And Obsolete is when the contents of the cache are stale and need to be downloaded again. Now in terms of browser support, you quickly get an idea that we're running into some of the same situations that we've done in the past with Internet Explorer. So at the time of this recording, Internet Explorer does not support offline applications, but many of the other contemporary browsers do. So it'll be up to you of how you choose to implement these applications in light of Internet Explorer not being able to handle it. But I would like to say though that since the HTML5 DOCTYPE switches the browser into quirks mode when it doesn't recognize the DOCTYPE. If the page has a manifest attribute applied to the HTML element, Internet Explorer will simply ignore it and the page will work as designed, it just won't be cached onto the user's machine. So, you're not down and out even if you're not supporting Internet Explorer.
Demo: Offline Events
To begin, I'd like to show you this page running and then once you kind of have an idea in your mind's eye of what's happening, then I'll go through the code. So to launch the page you'll see we're taking a look at the caching events that happen within this page. And what happened first was that the window loaded and then it started to check for the cache. Recognizing there was a change in the cache, it downloaded the files. Once all the files were downloaded successfully, the Update Ready was available and then we swapped out the cache. So now if I hit refresh you'll see that we have Load, Checking Cache, and No Update. So just to illustrate the point of what I've said before of the fact that you can make changes to your files, and I'll do that here. So we'll just call this Caching Events two, and so now when I return to the browser, I'll refresh the page and you'll notice that nothing really happens. Obviously behind the scenes it's checking to see if any changes have happened and because the manifest file has not been changed yet, the browser is not seeing any changes. These files are cached on the page and no changes happen until you come over to the manifest file, we'll call this version 1.1, and I'll go through all the details of the code in just a moment, but now when I refresh the page, you'll notice we're downloading items once again. The cache has been swapped out and then there's one last step that I must do, and that's refresh the page, because even though all of the information is downloaded to the user's machine, you still need to refresh the page once they're there in order to have them read into memory and displayed to the user. So now I'll take you through the code so you can see the mechanics of how everything happens. Now there's a big point I want to make right up at the front here, and that is that all of the techniques that I'm showing you are by no means dependent on any type of server-side technology. So I'm using Microsoft Visual Studio because I'm most comfortable in this editor. Definitely not required, you could do everything I'm showing you with Notepad if you'd like. I'm also using ASP.NET for a specific reason, but again, you could do this on a rail site, you could do it on a Java site, it doesn't matter. The only distinguishing factor and the only reason I bring all this up is that because you'll notice here that I have events.aspx. And normally I would do something like this with a file called events.html, but I have to bring in a little bit of server processing in order to prepare the HTTP headers the correct way. If you recall from the slides that I showed you about how caching can collide a little bit, what I need to be able to do is turn off caching for all the pages that I'm serving. Now you may choose to do that through settings on your web server, I chose to do it page by page because it makes these samples a little more portable. So you can download them and run them without having to worry about configuring a server or anything like that. So, to begin with I have this events.aspx page, which is an ASP.NET page, but you'll notice the code behind, and this is typically a place where we put in all the logic for a page is completely blank. There is nothing happening on the backend here. The only thing that's happening is that I'm inheriting from this class of NoCachePage. And if you're not familiar with object-oriented programming or any of the stuff, none of this really matters except for the fact that I'm turning off caching with this one line of code here. So, I'm setting the cacheability to NoCache. And again, you may do this a number of different ways depending on your implementations, but this is how I'm achieving this goal here with ASP.NET. So, bottom line, turning off caching for all the files. You'll notice here that I have my HTML page has been setup that way, my manifest page has been setup that way, even my style sheet has been setup to make sure that browser caching is not enabled. Okay, I think we're probably pretty clear on that one now. So, from the very top, we have the HTML document declaration. So once this is defined, then I have an attribute of manifest. This is how a browser knows that it's encountered a page that is part of something that's in the application cache. So the manifest is the page that we point to that has the long list of all the files that must be downloaded and downloaded successfully in order for the application to work. So this is the first clue that we're working with an application cache page. Everything else is standard stuff that you're used to doing all over the place. So I'm linking to a style sheet, I'm linking to some script files, I have my own script, nothing is different about this page and that's the nice thing about what I noted about Internet Explorer. Even though you may not be able to cache these pages, there's nothing inherently different about these types of pages, they'll work in browsers that may not support application cache. So next up, let's take a look at the manifest file. The first thing that I would like to point out, and again, you can do this on your web server, you can do it on the page like I've done, but you need to make sure that you set the ContentType on your manifest file to text/cache-manifest and ResponseEncoding to UTF-8. And this just makes sure that the mime type is set correctly for this file. Now at the very top, this is the important one, you need to make sure that your manifest file begins with CACHE MANIFEST. Don't try to put this comment above it or else you'll have problems, trust me. And then I have my comment here that allows me to handle the versioning, and the reason this is important is although you may make changes to these individual pages, unless you change the actual file names, there's no change that would happen within the manifest in order to reflect those changes. So, if you have a version comment somewhere within your manifest file, this will allow you to trigger any changes up to the browser when you do make changes to any of the files listed within the cache. Now I'm trying to keep this manifest simple, but at the same time use it for a number of different samples. So I just have all these files here listed. I have my events page and I'll show you some of these other samples to show you how to do manual and automatic, updates to the page when changes have been triggered with the manifest, and then of course I have support files that I need included as well. So I'm bringing a jQuery, I have an offline JavaScript file, which I'll show you in just a moment, and then also my style sheet that's been setup to not cache. So this is a very basic manifest file. If I go back to the HTML page, you'll notice that I've got some script running here on the page and this is after I've brought in my offline.js. So the offline JavaScript file, its intent is just to subscribe to all the application cache events and report back to the page what's happening. So let's take a look at this file really quickly. So, beginning here from the ready function, you'll notice that I'm checking to see if I have applicationCached. You can use modernizer or any other different ways of detecting whether or not this behavior is available, but I just did the simple way of checking to see if it's available off of the window object. And then from there, I'll log what happens by just basically appending some HTML to an unordered list. So I'm looking for Checking, Cached, No Update, Obsolete, Downloading, even if there's an error I might encounter, and then also when the window loads. So as each one of these events fire, I'm basically just writing a new list item to the unordered list. Now, with the different samples that I have available, I want to do different things when onupdateready fires. And if you recall, Update Ready is the event that's fired when we've noticed that there's a change in the manifest file. All the files are downloaded successfully and now the browser is notified that the update to the application is ready and you can do something with it. So in this regard what I'm doing is just saying that the update is ready and then I'm swapping the cache, because even though the files are downloaded, what's inside the browser window, what's in memory, what's being rendered to the user, still is that old version of the file. So you need to swap the cache out and then use some sort of mechanism to reload the page in order to finally render it to the user. So once again, we'll just call this Caching Events three. I'll run it one more time. You'll notice that Caching Events Three does not show up, however, if I come over to the manifest file and go to version 1.2, refresh the page one more time, I have everything downloaded correctly and then once I refresh one last time, you'll see Caching Events Three. So in the next demos, I'd like to show you how you can give some hooks to the user, or even do it automatically in order to do those updates.
Demo: Manual and Automatic Updates
In this next demo, I'll show you how you can give users control over when they see changes to the offline application. So if I run this page, the first thing that you'll notice is that it's checking, there's no update found. I can refresh, nothing's happening. If I make a change to the page and I make a change to the manifest, 1.3, now what will happen is as I refresh the page, the new version of those files are downloaded and made available. However, you have an application and maybe you make some wild changes to the application and things will move around. You might want to put a message up to the user to tell them that you have a new version of the application and you can give them an opportunity to "install" the application. And so now when I click on update, you'll notice that Manual Updates Two shows up. I didn't have to hit the refresh page, but I'm basically doing the same thing. So, the code is quite simple. If I come over to update manual, everything that you see here is exactly the same as the first sample that I showed you except for a few things. First, I added an input button to the page, and then when that input button is clicked, I'm just calling location.reload. So what this does for you as the developer is it makes it so that you don't have to require your users to hit the refresh button or press F5 in order to see changes to the application, and it also gives them an opportunity to take control of when they see the changes. Now that may be exactly what you want, or you might want the flipside. You may want to see something to where when a change happens, it's automatically brought up to the user's attention. So with automatic updates, when I run the page, you'll notice that we're at a state to where there's no update. Now I can come back and call this Automatic Updates two and then change the manifest, 1.4. When I refresh the page, you'll notice that something very quick happens. It downloads and you'll see all the events firing to download the new version, but then it will automatically refresh the page for me in order to show Automatic Updates Two. So if you get to the point where you just want to automatically show the new version of the application to the user, which will probably often be a preference for you, then you can implement something, which is basically the same thing we did in the other one except we're doing it without a button. So as soon as updateready is fired, and if you remember correctly, updateready is only fired when the applicationCache is changed so you know that all the files are on the client and ready for you to use. So you can call swapCache and then just call location.reload. Now all this may seem like little bits of trivia, but these are actually very important mechanics that you'll need to know in order to make sure that the version of the application that your users are running is the one that you expect.
Demo: 'Always On' Journal Application
At the beginning of the module, I made the distinction between the fact that offline applications are really the summation of two things. You have the application cache API, I've shown you a little bit about that, and then you have the browser's ability to recognize whether or not there's a connection to the internet present. So if you'll notice this is the journal application that I'll show you how to build, and one of the features of this application is an awareness of whether or not the app is online or not. So take a look up here in the right hand area and what I'd like to do is turn off my wireless radios here. So I'll switch those off and you'll see here that all wireless radios are off. Click OK and no changes, no smoke and mirrors. Online is now set to No. And so now that I'm disconnected from the web, I can maybe start journaling. Let's say I'm a sales representative and I want to create some notes about some of the clients that I've seen or something like that, just out in the field. So I can just say test one, Send. Notice down here it says message saved locally to test one. I can say test two and I can do this all day. Now what happens in the way that I have this application setup is that as soon as it recognizes the presence of an internet connection, it'll take the messages that are saved into an array, loop through those messages, and send them off to the server. So notice here when I connect back up to the web, you can see that they're now turned on. Watch up here you'll see that Online will soon say Yes, and then down here you'll see the messages saying that it's sending the entries off to the server. Now, this is an important distinction to make, and that is that the application sending to the server is under local host and under this port. So, it's not an issue of whether or not this page is being served from the web or not, because once you have a page that's been setup with applicationCache, it's always served from the cache unless something is changed within the manifest and it goes and grabs the newest version and brings it down. So it's not whether or not the pages are coming from the server or not, it's truly an independent flag that says whether or not there's a connection to the internet. So even though I'm talking to the server on my local machine, those messages weren't sent to that server until the application realized a connection to the internet is available. And so now I can create some more messages here, so I'll just call this, where'd we leave off, three, just four test and then five test, six test. And you notice that those entries are being sent to the server immediately, but then once again, if I happen to lose my connection to the web, which I just did, Offline is now set to No and I can do seven test and eight test. Those are buffered in memory on the browser and once I get connectivity back, they're automatically sent off to the server. And you'll see those messages down here in just a moment, and there you go. So let me take you through the mechanics of the general application. To begin our discussion on the code for the general application, I'd like to start with the manifest file. And you'll notice the same things that you've seen in the past. We've got the ContentType setup, the encoding type, CACHE MANIFEST at the very top, and our version comment. I do though have some other sections available within this manifest file that I didn't have before. So I have NETWORK and also FALLBACK. So, Network is just an area to tell the application cache never to try and cache any of these pages. It's something that we need the server for. So if I wanted to take a look at all the messages that I'd saved in the past and need those listed off, well I'll need the server in order to do that. The Fallback section says instead of trying to serve something up for the homepage since we're offline, I can automatically show journal feedback. Let me show you how that works. So I have this link, if I click on Home I go to the offline page and you notice it serves it up from memory and it doesn't change the URL and it says the journal is currently working offline, continue your thoughts here, and I can go back to the journal application. So as we come back to the code, those are the different sections that you have within the manifest file. And the fallback is just a regular HTML page, again setup to make sure that there's no caching, but it's whatever you want to show to the user if they go to a fallback page. So the real fun happens within the journal file here and I'll take you through the code that's needed in order to be aware of the presence of an internet connection and how to respond to those changes. So, I'm going to skip ahead on some of these a little bit and start down here with what happens when the page loads. So the first thing I'm doing is setting up a few housecleaning things so I need to know that the journal textbox that's on the page and I'll set that aside so I can use it over and over again. The sendButton is the button that you click once you are done writing a message and I'll come back to that in a moment. The real interesting part of what's happening right now is what happens when the browser recognizes that you're either online or offline. So the first thing that I'll do is report the online status up to the browser and this basically switches that online message to the Yes or No. When I'm online, then I can take all the messages that have been saved in an array on this page and go ahead and just fire those off to the server. But if I'm offline, then all I'll do is update the page so that you can see that you're offline, and then the logic that handles that handles how to save the messages will worry about whether or not to save it in an array or send it directly to the server. So at a high level, what I do is I have an array that I shove each one of the messages into and if I have an internet connection, I'll loop through any contents of that array and send it off to the server. So if there's already an internet connection, the messages are put into the array, but then immediately sent out to the server, so it just kind of clears it automatically. But if you're offline, that array begins to grow and so then once you have that internet connection, you can cycle through each one of those and send it off to the server. So that's what happens when the browser figures out whether or not you have a connection to the web or not. So let's take a look next at what happens when we go to store a message. So as the page attempts to store a message, the first thing that it does is it extracts the value out of the textbox. So whatever message I typed into that text area, I'll set it aside here and can do something interesting with it. So then I'm looking to see whether or not if I'm online. So do I have a connection to the web or not. And so that's wrapped up in this function and I'm calling window navigator.onLine. And this is the property that will change when you lose or gain connection to the internet. If I'm not online, then I'll store the messages locally, but if I am online, then I'll store the messages remote. When I store the message locally, just like I said, I have an array prepared. I push the messages into that array, I clear the UI by basically just clearing out any of the text that was in that textbox and then log the event saying the message is saved locally within the array. When I store the message remotely, then I push a new message onto the array and then send those messages to the server and then clear the UI. Sending the messages to the server is just making a simple AJAX call. While I have values within those messages, I'll pop an individual item off and then take the message that was once in that array and then send it off to the server. Here I'm sending a JSON message to an ASP.NET controller and I'll show you the implementation for that next. So what happens on the server really isn't all that important and basically this is just demo code here. This is a controller for ASP.NET and MCV and if this looks really foreign to you, that's fine. If you were setting up an application like this in the real world, you'd have some sort of server component. And whatever you're used to is what you would use. But in this instance, all I'm doing is passing in what amounts to a JSON message to this server side area for processing and I'm just basically doing nothing with it and sending a response out. So there's no magic happening here. This code here just gives a response back up to the browser to know that the server has been contacted and something happened.
Demo: Manifest Errors
Now as you get further and further into your development of offline applications, one of the things that you'll run into is you'll encounter errors that happen when you try to download the files. The only problem is that the error information that's returned back to the client isn't really all that verbose. So you notice here that I have an error event that's happening. And if I open up the web developer tools within Chrome, you'll notice here that I get a little hint of what's happening at least within my manifest file. So I'm getting a 404 on one of the items that's in the manifest. And so if I go back to the code you'll notice that in fact I'm not looking for debug.asp, I'm looking for debug.aspx. And so now when I reload the page, I have a successful load. So this just drives home the point that unless all of your files download successfully, you won't have an update to your application. So it's good in a sense to know that when the page loads without error, all the files that are necessary in order to make the application work are downloaded together as a package.
Summary
Well once again, thanks for joining me for Pluralsight's Advanced HTML5 in this module on Offline Applications. In this module, you had an opportunity to work with the application cache API and see the different events that are fired which allow you to interact with the application cache. You had an opportunity to see how changes to the manifest are really what power what the user sees and how you can give control to the user to decide when to see things or show changes to the application automatically. Beyond that, the journal application clearly illustrated how being able to respond to whether or not you're connected to the web can make a huge difference in how you build your applications. Lastly, we took a look at how to find out if you have any errors in your manifest file, which help drive home the fact that all the files within your application are downloaded together as a package giving you the certainty to know that all the files that are grouped together in an application are available once you have a successful download. This is Craig Shoemaker, and thanks again for joining me here on Pluralsight.
Fundamentals of HTML5 : Geolocation
Introduction
Hello and welcome to Pluralsight's Advanced HTML5 in this module on Geolocation. Now geolocation is one of the topics that actually is technically not a part of HTML5 anymore. What had happened in the past, a number of technologies had been grouped together into the title of HTML5, but in order to keep things tidy, a number of technologies were split out from the actual HTML specification. So, while geolocation is often thought of as part of HTML5, it's actually its own specification. But that trivia aside, what we'll talk about in this module is what exactly geolocation is, review some of the request patterns, some of the options that are available for you. I'll show you how the position is calculated, delve into some of the browser support, and then I've got some demos for you that will show you how to get the position of the device, how you can watch the position for continual updates, and there's some options available for when you're watching the position.
What is Geolocation
So what exactly is geolocation? Well it's the ability of a web browser, at least in this respect, it's the ability of a web browser to be able to communicate with the outside world and find out where in the world that device is located. So geolocation may be used for many, many different applications, but often you'll encounter the need for geolocation when you're building mobile applications, or at least an application that needs to be aware of where the person actually is. The request patterns that are available to you are either of the opportunity to ask for the location of the device one single time, and maybe you're building a movies application and instead of requiring that someone puts in their zip code, you could use geolocation to find out where they are and show them movies that are available in their area. Or you may want to setup your application to continually ask for the coordinates or the position of the device. And this might be useful if say you're building a mapping application. But either way, the requests for position go out asynchronous to the browser and so you'll make a call out to request position, some time will elapse, and when you get a response back then you can do something with that information. Now let's review some of the techniques that are used in order to calculate location information. So, the first approach is IP address, which is nice because it's available just about everywhere, just about any device that's connected to the web ends up resolving an IP address. Processed server side, which is great so it doesn't take up resources on the client machine, but unfortunately, it can be quite inaccurate. In fact, if you've ever done the search of where you are in the world on the web, especially if you're going through say a proxy server, the location can be hundreds of miles away from where you actually are. And sometimes in order to find out that information, there's a number of different servers that have to resolve within line, a number of different hops that have to be made in order to figure out the final IP address to report. So IP addresses are one way of figuring out where you are, but not always the best option. GPS is another approach that can be used, which is great because it's very accurate. The only problem is sometimes it can take a while to figure out the location information and the coordinates. If you're indoors, if you're in a parking garage, GPS might not work so great for you, and obviously you have to have a device that has a GPS on it, so the right kind of cell phone or the right kind of handheld device. Wi-Fi is another technique available, which is generally pretty accurate. It does work indoors. It can give you a quick response, but it requires that you do have Wi-Fi available everywhere. So if you're out driving on the freeway and you happen to drive by a Starbucks, you might be able to get Wi-Fi connectivity and then it might quickly go away. So, you have to use the right tool for the right job in many cases. Cell phones can give you excellent reporting on exactly where you're at. So they're very accurate, they do work indoors, quick response, but you do need the device, again. You need the cell phone and you also need to have service available, so in rural areas being able to rely upon cell phone access in order to do location information may be difficult. The final thing that people often overlook is user-defined, and obviously hopefully, unless you've had some really late nights out, you know where you are in the world. And the other thing about being able to have user-defined location information is that let's say that I'm in Southern California, but I'm going to Colorado to visit my family. Maybe I want to add in a zip code so that I can look up some restaurants or things that I want to do while I'm there. So it gives you a little bit of flexibility to designate alternate locations. And ultimately it may be the fastest option because if you're waiting on a bunch of these servers to resolve and figure out where you're at, it could be much faster, but it also can be inaccurate in the same sense because unless you make sure that the user has updated this information when they move, you can report some results that are incorrect. So the idea is that there's all these techniques that are available in order to figure out information and what the browser will attempt to do often is figure out the path of least resistance in order to find the location and then it may make further requests in order to constrict the accuracy even further. And so all of these approaches may be used when trying to figure out the device's location.
Geolocation Options
Now when we're talking about calculating location information, there are some options that you do have available to you. And you'll see these at work in a sample that I have for you, but I want to review them here at a high level so you can understand what's encompassed with them. So there's a flag that you can turn on for high accuracy when you request location information, and it's just a simple Boolean and it will attempt to gather more accurate location coordinates. And so it may go through that cascading list and it may go in different order than what you saw on the slide, but it may attempt to try and get, again, more accurate information back to the browser. But at the same time, it may not do anything because some of the requests may fail or some of those options may not be available, so it could cause a request to take longer, but if you need the most accurate information possible, you may consider turning on this flag. Now there's two other options that seem like they're kind of similar, but I'm going to help you draw a distinction among them, and that's the timeout and the maximum age. So, the timeout is measured in milliseconds and it tells the browser how long do we need to wait in order to figure out that this request for the location really isn't working. The default is no limit, so if you find that your application tends to spin a lot and doesn't really return that information fast enough, then you can set a timeout on it so that you can get a callback and then do something else, maybe after a certain amount of time you can allow the user to add in their zip code or get an idea of where they're at some other way. So, that's timeout. It's basically telling the browser when to stop trying to request that information. Maximum age is a little bit different because what it does is it says, okay I have some location information, but how stale is it. So it just determines how old the location value needs to be before you attempted to get a new version of it. It's measured in milliseconds and if you set the value to 0, which is the default, it's an immediate recalculation. So tuning this property may help with performance on your application as well. If you only need to request new location information at certain intervals, then you may want to fine tune the maximum age property.
Browser Support
When we take a look at the browser landscape, delightfully, all the browsers, all the major browsers support the Geolocation API. Now different browsers may return a different amount of granularity when it comes to the location information, and you'll see what I mean in the demos in a moment, but you at least get the basic functionality of getting latitude and longitude coordinates back from your request for location out of the browser. Now speaking of the browsers, each browsers that the UI for each browser handles it just a little bit differently, but when you make a request for location, there will be some sort of notification to the user allowing the user to allow or deny access to their location information. Some browsers request permission every single request and other browsers will keep that setting available on the client. Now, as you're developing your applications, often what you may want to do is reset the location permissions just to make sure that the popup for asking for permissions shows up at the right time and you know how everything is working. So with Internet Explorer you go to Options, Privacy, Location, and Clear Sites. Figure that out that way. With Chrome, it's a little more involved, Options, and you go to Under the Hood, Privacy, Content Settings, Location, and then Manage Exceptions. What's nice about this window is that you can decide on a domain by domain policy of whether or not you want to keep the permission of being able to share location information. The other thing about Chrome that makes it nice is that if you see this string in here, if you paste this string down into the location bar on chrome, this will take you all the way through to the window that allows you to manage that information, so you don't always have to go through the menus, if you keep this around you'll be able to go directly there, which is nice. Safari, Firefox, and Opera process each request individually, so there's no reset that you need to worry about.
Demo: Get Current Location
The first sample that I have prepared for you here is a simple sample that shows how to get location from the browser. And what I want to do before I get the values is show you what the confirmation screen looks like in each one of the browsers. So in Chrome, you get a window that pops up that looks like this. In Internet Explorer, your window shows up down at the bottom and you can allow once or configure options for the site. Firefox will pop it up in this fashion. Opera is obviously a little bit different, you get this banner up at the top. You can remember the choice for the site, Share My Location. And also with Safari, you get a modal dialog. So this is important because as you build your applications often what people might want to do is show a notification or even a screen shot that says click on this button in order to allow. But you need to be aware of the fact that different browsers handle this in different ways. So here we are back at Chrome and let's do this once again. We'll Get Location and Allow to get the value. And so now we have latitude and a longitude and even an accuracy value coming back from the Geolocation API. Now, once I have this information, what I can do is then use it in any way that's useful. So here I'll view a map and you'll notice here that this gave me a map to Disneyland. And while I'm not at Disneyland right now, I masked my actual home address because the accuracy of the location information that comes back from my house is pretty darn accurate. And so I'll wait to send you an Evite when we're ready to have a party here at the house, but let's go ahead and take a look at the code that's involved with this sample. First, just the structure for the sample here is header and then I have these input sections that allow me to add in each one of the values that come back from the Geolocation API. Nothing too earth shattering here with the HTML itself. The fun happens when we get down into the script, and so on the ready function of the page, at the top here I'm just creating jQuery instances of some items that I need to manipulate later on in the page, but the real meat of this sample is when you click on the getLocationButton. From there, we're calling navigator.geolocation.getCurrentPosition. And then I'm passing in a callback to this showPosition function and also a callback to the positionError. So once showPosition has been called back, it has the information, then I can grab information out of the event args, which I've labeled position here and then get the coordinates. From those coordinates, I have access to the latitude and the longitude. And this part here is just again the coordinates to Disneyland at the moment. But you also have availability to accuracy, and this in value of meters with about a 95% accuracy rate. If you happen to be on a mobile phone and in a plane, you might get a value of altitude returned and the same thing goes for the accuracy of altitude. The heading will tell you in what degrees you're going relative to true north and speed gives you the ground speed in meters per second. The timestamp basically tells you when this value was calculated. So once you have that information, then you can take the latitude and longitude and pass it to a service, you can save it, you can do whatever's necessary at that point. For errors, there's a number of different codes that you may want to specifically code against. So, there's the all fun and games, unknown error, and who knows what you're going to do with that one. But the PERMISSION_DENIED error will fire if someone denies to share their location with you. So let's take a look at that for a moment. So here I have the same page here. If I say Get Location and I say Deny, down here it says you chose not to allow this application to access your location. And that's exactly what I had here logging that message. So, the error function was fired and based off of that code, I was able to deal with it. POSITION_UNAVAILABLE is if all the different techniques used to try and figure out where you're at, those all fail, then this error code will be returned. So this might be a place to where you want to trap for position unavailable or unknown error and try and give the user an opportunity to tell you a little bit about where they are. And then at least your application can still get a general idea of what type of information it needs to return to the user. And then finally, TIMEOUT. If the request is taking longer than what you've setup for a timeout, then this error code is returned. And so this is basically the format that you'd use if you need to get location information one time. However, if you want to continually get updates about where the user is, then you have to change your request for information just a little bit.
Demo: Watch Position
The second approach available for getting location information is instead of just getting the current position, you watch position. So I can click on Watch Location and any time I change my location, it will report back to me the change. The only problem is right now is I'm sitting at my desk recording this for you and so I'm not moving, so I won't have a change in location. But I'll show you the API and how it works. So, you can start by watching the location and then you can click Stop and then here you can see that we've stopped watching for the location information and again just take that information, you have latitude and longitude information available and some of the other attributes, if they're being returned to you and you can do something interesting and useful with it. So with Watch Location, the structure for this page is exactly the same as the last demo that I showed you. The difference here though is that you're setting aside a watchID. And so you can spin off multiple watch IDs if necessary, but this gives you basically the unique identifier for this watch position that you're tracking. From there, you call navigator.geolocation.watchPosition, instead of getCurrentPosition, and then it's the same signature. So you have a success callback and you have an error callback. So when you have a successful return of information then basically you have the same values available to you. It's just the position and the coordinates, accuracy, altitude, on and on and on. And even error function here is exactly the same as what it was before. So the distinguishing factor is that you just simply call watchPosition instead of getCurrentLocation and now you have the ability to get continual updates. Now if you need to turn off tracking of watching the position, then you go to navigator.geolocation.clearWatch, and then you pass in that watchID. So here you have very granular control of which ones that you can turn off. If your application did have a need to be watching positions in more than one instance, then you can manage that here.
Demo: Position Options
The final sample I have prepared for you shows you how you can pass in the value used for show position options. So if I do a Get Location, you'll notice that my accuracy here is 49 and it's basically the same value it was before, so by fine tuning, enabling the high accuracy option, it doesn't really do anything for me right now, but I'll show you at least the syntax of how it works. So again, the HTML is exactly the same and the only difference here is that I'm creating a JSON object here of options. And so enableHighAccuracy is set to true, timeout is about 10 seconds, maximumAge is 1 second because these are all in milliseconds, then when I call getCurrentPosition I have the callback for showPosition, the positionError, and then I can also pass in the options. And so, when you come down to showPosition, all it does is it tries to give you more accurate values when you're down in here looking at the position information.
Summary
Now that you've had a chance to see geolocation action, you see that it's the ability to get the device's geographic location. It often amounts to a best guess. Now that best guess can be very accurate, but accuracy levels do vary, granularity levels do vary, but you're at least guaranteed to get a latitude and longitude coordinate. There are options for fine tuning the data that you get back and depending on your application, you can setup the request to be one time or continually updated. Well thanks again for joining me for Pluralsight's Advanced HTML5 in this module on Geolocation. This is Craig Shoemaker and I hope you join me for the rest of this course here on Pluralsight.
Fundamentals of HTML5 : Web Storage
Introduction
Hello and welcome back to Pluralsight's Advanced HTML5. This is Craig Shoemaker, and in this module I'd like to teach you about the new Web Storage API. So to begin, I'll introduce you to web storage and also show you some of the features that you can come to expect from the API. And then I'd like to compare and contrast it with some other storage types that you may already be familiar with. Then I'll let you know what you can expect in terms of browser support. And then for the demos I'll take you through a task list, a shopping cart that's completely implemented in the browser, and then we'll go through some of the particulars of the API showing you how you can clear out the storage, how to deal when you've hit the size limit in the browser, and also how to handle the storage event.
What is Web Storage and Browser Support
HTML5 Web Storage, well what exactly is it? Well first of all, you'll notice that when you do your research, sometimes the information on web storage emerges under a different name. So whether you find information on DOM storage or web storage, it's basically all the same API. And web storage comes in two different parts, or two different flavors. The nice thing is that the API remains the same whether you're using it under local or session. So local storage you can think of much like a cookie. So you're able to write information to the user's machine and have it available at different times. And session works exactly the same way except the fact that the lifecycle for that information is only available throughout the user session, so across page refreshes, across different tabs even, but once that session is done, that information goes away. With local storage, you have the ability to come back even after the browser window has been closed and pull that information back up off the user's machine. When we talk about security, you have access to that information, when you're going through session data, basically per session, and it's also constricted per domain. The capacity that's available is what it comes down to is being client controlled. So, depending on the browser, you have anywhere from 2-10 MB available as a basic configuration in the browser. Often it's around 5 MB, but some browsers allow you to control how much space is available, but obviously there's a lot more space that's now available to you within web storage than maybe what you'd been used to in the past if you were trying to use something like cookies. So cookies are the basic frame of reference that we have to work with when we think of persisting data on the client. And cookies are great, but obviously they have a much smaller capacity than what you have available within web storage. The other distinguishing factor between cookies and web storage is that since there's so much data available, one of the things that does not happen with the web storage data that does happen with cookies is that that information is not sent to the server with every request. So the data is not sent across the wire every time you request a page, it only stays on the client, so completely client only. Now that has some implications. Obviously from the server, you can't write to web storage, but at the same time, it keeps the requests down and so you have the ability to save a lot more information on the user's machine. One of the concepts that you may be familiar with or not is the idea of the index database, and this is a new client-side database that's emerging as one of the HTML5 standards. And people often wonder, well why do web storage and indexed DB need to even be a part of the picture. Well web storage is a much more simple API than what you'd be looking at with indexed DB. Web storage is basically a key value pair and there's no querying language for anything. If you think of how you used to program cookies, but yet you have much more space available, now you're kind of thinking in the right direction of how you might want to use web storage. And the other nice thing is that it's available in many different browsers today whereas indexed database, although it's much more robust and has much more capability to have true database-like qualities on the client, it's still mostly being developed as of this recording. Delightfully, when we take a look at browser support, the Web Storage API is basically supported across all the browsers, all the contemporary browsers at least. Internet Explorer, which often has a difficult time keeping up on some of these standards, from version 8 on has the ability to support web storage. Interestingly though, when you take a look at one aspect of the Storage API, there is a place where Internet Explorer 9.0, so IE 9 and up, supported the storage event. And while the other browsers support the API, they do not support the storage event. So in the sample that I'll show you regarding the event, you want to make sure that you run it in Internet Explorer 9. A quick overview of the API shows you that it's a very simple API to learn and you'll have an opportunity to see each one of these items in action. And so with that, let's dive on in to the demos.
Demo: Persistent Task List
The first web storage demo that I'd like to show you is a sample that uses local storage. And the way this sample works is that let's just say we have some sort of task list, there's some things that we need to do today, go to the store, wash the car, and maybe feed the cat because it's been a couple days. And so now we can save that task list and what's nice is that if I close the browser window and I open it back up, you can see that the values are still there. And if I delete it, you get the same type of functionality. So using local storage is the ability to save data on the client's machine regardless of session, whether the computer turns on and off, it's just data saved on the computer. For the code that's required for the sample, let's go ahead and take a look at the structure first. I just have some header tags here, which identify the sample, a container for the message, so when you see saved or deleted, and of course the textbox in order to do data entry, the saveButton, and then also a delete link. Down when we get into the JavaScript, when the page loads I'm setting aside the textbox and the message container and then detecting whether or not I have local storage. So the way I'm handling this right now is that you could choose to do it any number of ways. Since localStorage is a key pair value type of setup, I could have created a key for each one of the items in the taskList and added those into localStorage. Rather than doing that though, what I did was I created a single key for the entire taskList. And the way it works is that if I'm saving it into localStorage, I'll take all of the values that are on separate lines, combine them up into a single string, and persist them in, and then if I'm reading those values back out, I'll split the lines based off of a delimiter and then add the line breaks back in to put it back into the textbox. So that's exactly what I'm doing here. I'm looking to see if the localStorage, if the taskList is not null, so if that key exists, then I'll grab the values out of localStorage based off of the taskList key and then I'll split on the comma, which is what I used to replace the line break when I'm doing the saving into the taskList, and then I set all that information as the value to the textbox. And so saving the information is just the inverse of what I just said, so I grab the value out of the textbox, I split on the line break, join it with a comma, and then set that value equal to localStorage.tasklist. When I want to remove the item out of localStorage, then I can access localStorage and call removeItem, passing in the key that I would like to delete. And by doing that, that removes it out of the localStorage memory and then from there I'm free to update the UI in order to reflect the changes.
Demo: Session-based Shopping Cart
Now that you've had a chance to get acquainted with local storage, let's take a look at session storage. So here's like a typical shopping cart type of application and you can fill in your name, Craig Shoemaker, Email address, futuristic internet-enabled contact lenses, well I think I'm going to need two, one definitely for each eye, and then once I have that I can go to the summary page of my shopping cart and you can see that there's all the same values. Now what's interesting to note is let's take a look at the cart review page first. You'll notice here that there's, this is a completely empty page. In fact, if I were to open up this page under another browser, let's just go ahead and do that, you can see that nothing is there. All the information is being pulled in from a session. Back to the cart add page. So this is the very first page that you saw and for the structure of the page I have a couple input types, I'm looking for text and then Email, I'm autofocusing on the name and I've got the placeholders here to give the user an opportunity to know what we want to put in there, so Name and Email. And then I've got a typical table here and I have it auto-populated with a value for one of these little contact lenses here. You may or may not be familiar with this type of an attribute within an HTML element, and this is something that's new within HTML5 is well and it's the data-attributes. So in the past with XHTML, you weren't able to add your own attributes to the markup because they wouldn't validate, but with HTML5, we kind of understood that it can be very, very beneficial to have the ability to add your own attributes into HTML elements. So as long as you prefix your custom attribute with data-, that will validate and work well in real world scenarios. So in this case, what I wanted to do was add in the numeric value to the element, but then also show the formatted value to the user as what's inside the text, so this worked out well. And then the rest of the form just has a numeric input type for the quantity and then once the calculation is made, I use this span in order to show the extended price. So as far as the script is concerned, every time the quantity changes I'll calculate the cart. And cart calculation is simply done by looking at the price element and extracting the data value out of there, parsing it as a float because I'll have a couple decimal points that I need to make sure I account for. Quantity will be an integer, so I'll get that out. And then finally to get the extended price, I obviously multiply price times quantity. This toFixed will make sure that I have only two decimal places when I report the final value out. So that's the calculation, but when I go to the next page this is where I want to begin to use session data. So what I did here was created a JSON object that represented all the data that I needed to pass to the next page. And so this has the name, the Email address, price, quantity, all the information that's gathered within the form. Once I have all the data available, then I can access sessionStorage and then I was just using JSON.stringify in order to create a string out of that JSON object and then I can set that dataString to a key in session. So setItem, key of cart, pass that in, and then the last thing I have to do is just navigate to the other page, so window.location.href and that goes into cart-review.html. So we looked at that just briefly. So the script that's required to get the information out of session as you might guess is very, very easy. So I'm getting reference to session. So then I'm using my cart key to grab the information out of session and then parsing it as a JSON object and once I have that JSON object, I can simply update the HTML elements with the values that I come in from session. So once again, it's the exact same API that whether you're writing to local storage or session storage, and it makes it very easy to work with and very easy to create pages that use web storage.
Demo: Handling the Storage Event
This next demo demonstrates how to handle the web storage event. Now if you look carefully, you'll notice a little difference in the browser that I'm using. So before, most of the time I've been using Chrome because that's my default browser. Right now, I'm using Internet Explorer 9 and if you recall from the slides, that's because this is the only browser at the time of this recording at least, the web storage storage event. So if we do the same type of thing that we had before and we have our task list, we have different things that we want to do, and click Save, you'll notice down here that the storage event fires and I can get access to some interesting pieces of information. So you notice I have the Key that's being written to, I have the New Value, and I have the Old Value and it didn't exist before so there is no Old Value, and I also get the Url. In the code you'll see, there's another piece of the event that exposes view, and that gives you reference to the actual web storage instance. And what that means is that you get the access to whether or not you're writing to a local storage object or to a session storage object. So the idea is you can create some generic code around this storage event and you don't have to worry about whether it's writing the session or local storage. Now if I change these values and I switch them to, say numbers, and click Save, you'll notice here that the New Value and Old Value update once again and if I hit Delete, you even get, as you might expect, the New Value being nothing and the Old Value being what it was previously. So let's take a look at the code. What we have here is basically just an extension of the previous sample. And so the structure of the HTML has been updated in order to create the fieldset, which exposes out the key New Value, Old Value, and Url. One of the biggest things that's changed is that now when the page loads, so you notice up here we have the jQuery ready function, down within that we're calling window.addEventListener storage, and then we're pointing to the displayStorageEvent function. And what the displayStorageEvent function does is simply grabs the values out of the event args and we're looking for key, newValue, oldValue, and url. So it just takes those values and plugs it into the spans that I have setup up above in the markup. And again you'll notice here that we have the opportunity to access the e.storageArea and this will reference either the local or the session instance used to save the data on the client.
Demo: Access Methods
Now one of the things that continues the ease of use of this API is the flexibility that you have in order to be able to use different types of ways, or different types of approaches in order to set and get values out of web storage. So if you'll notice here, if I'm calling local.getItem passing in the key, I get a value of value 1, or I can do local and use the dot operator for key and get the value out, or you can access your variable and pass in the key through brackets and get the value out of it. And so these different types of access methods will be valuable at different times and different ways in which you're processing data. So if you have to access say the values through a for loop, well this third option here may be very valuable to you. If you're trying to keep your code real clean and maintainable, the dot operator approach may be very valuable to you. And so there's a number of different ways that you can accomplish the same thing. So if we take a look at the code, you'll see that I'm doing local.setItem, passing in the key, and then passing in the value. And right here you'll notice that I'm hitting the variable and using the dot operator. This key has not been created yet, but I can go ahead and call key2 and give it its value and it will successfully add the value to that key, and the same thing here when I'm using the brackets. Key3 does not exist until this line runs. I can call key3, it knows to create that key and then add in the value. And so when I'm pulling the information back out, whether it's local or session storage, it doesn't matter. I can call getItem, access the dot operator or also use the key within the brackets.
Demo: Handline Storage Limits
Now if you recall from the slides about capacity, I talked about how web storage has its limits. And what this sample intends to do is show you where the limits are and also what happens when you hit that limit. So if I click Start, I'll just start writing a whole bunch of stuff into local storage and also into session storage. And so in a moment what will happen is that there we go, QUOTA_EXCEEDED_ERR 22. And so this is a DOM Exception that happened for Local Storage and also for Session Storage. So if I scroll all the way down here, you'll see that it was just writing, writing, writing, writing until there were only about 1841 bytes left and that value will probably match over here on Session, which it did. So I'll show you how this sample is implemented, but the main takeaway that you need to know about is that you want to be able to trap for this error so your applications can account for the fact that there may not always be as much space as you would like on the client's machine. So here's the code and the structure for the page is we've got a couple buttons on there, stop, start, and clear, and then I've got some containers here and all I'm doing is writing unordered list items formatted to report back the data and size that's being written into each of the storage mechanisms. Now, one thing I do want to point out is if you'll notice that this page was running within Internet Explorer. And that's because the remaining space variable is available in Internet Explorer 9. If we run this same page in Chrome, you'll notice I've got a little message that pops up here, and that's because the Remaining Space property does not get a value in any other browser, at least at the time of this recording except for Internet Explorer 9. So, you'll still get the QUOTA_EXCEEDED_ERR firing, that event will fire when you run out of room, but what you don't get is a report back of how much space is remaining, which depending on your implementation may or may not be valuable, it all depends. So that's where I'm writing the information in as we go along and then also when the errors popup I'll write to this unordered list. So, once the page loads, I get reference to all the UI elements that I need, so the local, session, and errorList. I'll also setup my click events for each of the buttons and so when the operation has started, I'm just doing a setInterval, so every 10 milliseconds the code in here will fire and what's happening within this code is I'm basically just taking a long string here, you'll notice I went and got some Lorem Ipsum text and just writing that over and over again into local storage in order to try and fill that up. This reports back to the user what's happening, so the storage length is being reported here, and that's a property off of the local storage object. So I get the length and also remainingSpace. And like I said, remainingSpace right now is only in Internet Explorer 9, hopefully that will change soon. The key to handling the error though is to make sure you wrap this operation in a try catch block. And so when the error happens, you can detect whether or not it's the error type that you're looking for. Here I'm just reporting it onto the screen so that you can take a look at it and then stopping the interval from ticking any further since we've hit the limit. And then at the very last end of this procedure after each interval is run, then I increment the keys so that we're writing to another key. And the implementation is basically exactly the same for session. It's no different except I'm writing to session storage instead of local storage, exactly the same. Again, the important part being having the try catch block and making sure that your application responds well to the event that you run out of space on the client. And so the other interesting piece to note within the sample is that I have the clear button. And if you remember what happens here when I hit Clear, what happens is it removes everything out of web storage, Local and Session, and kind of cleans up the UI. So, what you need to know is that you can call localStorage or sessionStorage.clear and that will remove everything out of it. As you saw in the last demo, there's ways that you can go in and remove items specifically by key, but if you simply want to clear everything out in one shot, all you need to do is call local or sessionStorage.clear.
Summary
Well in summary, you've had an opportunity to get acquainted with the Web Storage API, seeing how you can use local and session storage in order to save information on the client. Obviously session storage is only available throughout the user session and local storage will persist even through to closing the browser and opening it back up. Contrasting web storage to cookies and other techniques that you might be familiar with, you'll notice that web storage has much more space available to you and the data is not transmitted with each request and while you have more space available than cookies, some browsers allow the user to control how much space is available. So that means two things, you may have more space available than maybe what you first think, but you also might have less and so you need to make sure to keep that in mind as you're developing your applications. Well this is Craig Shoemaker, and thank you once again for joining me here on Pluralsight for Advanced HTML5, and this Module on HTML5 Web Storage.
Fundamentals of HTML5 : Web Workers
Introduction
Hello and thanks for joining me for Pluralsight's Advanced HTML5. This is Craig Shoemaker, and in this module I'd like to acquaint you with Web Workers. I'll start off by helping you understand exactly what web workers are and we'll explore some of the restrictions, then go over the browser support, and then dive into the demos. So calculating Fibonacci sequences is quite processor intensive. So I'll first show you what it looks like without a web worker, and then we'll refactor that sample to use a worker and see what happens after that. I'll show you how you can post string messages, as well as JSON messages to the worker and also some controls that you can do when you're working with web workers. Finally, I have a sample that'll show you how you can integrate AJAX calls directly within a web worker. We'll finish everything up with some resources that you may find useful for you in your research after you finish watching this video, as well as some ideas of how you might use web workers in the real world.
What are Web Workers and Browser Support
What exactly is a web worker? Well, it brings background threading as a first class citizen to web browsers. And basically if you have any sort of intense processing that needs to happen, you're able to splice off that logic into a worker and it'll run independent of the UI thread. Now there're two types of web workers. There's dedicated, as well as shared workers. A dedicated worker is linked to the browser window that spawned the worker, so it has a very tight relationship with that window. A shared worker is a worker that runs in the background and basically any script that's running within that domain can send messages to that worker. This module focuses on dedicated workers as shared workers are largely unimplemented in any of the browsers at the time of recording. Now if a web worker is basically a thread that works within the browser, you have the ability to take some sort of processing and have it run in the background. And that works great, but you have to understand that there's a few restrictions that you have to keep in mind. First of all, you have no access to the DOM, so you can't get at any of the HTML or any of the input fields, all of that is completely abstracted away from the worker in order to keep it thread safe. So the UI is just kept separate in order to make sure that the worker can run unencumbered. So you don't have access to the DOM and you don't really have access to the window except for maybe a few exceptions where you can get it some read-only information like the location.href and you don't have access to the host page. And that has a little bit of an implication for you. So if you're used to using say a popular JavaScript library like something like jQuery, well you won't be able to use that within a web worker because libraries like jQuery take a dependency upon window. And so if you're doing some AJAX calls, you're doing anything else that is made easier by using some of these libraries, just understand that you may not be able to use them as is. So you might be able to find libraries that fill the purposes that you need and don't take those dependencies, or you can implement some of the features that you're looking to do by hand. In the sample that I have prepared for you for AJAX processing, I'm just using the XmlHttpRequest object raw without any sort of a wrapping library. And so you'll have to figure out exactly what you're trying to do and find the best tool for the job at that point. While those restrictions do exist, you do have access to a number of API members that you're probably very used to using that will help you make robust workers. So you have access to the Navigator object, which gives you things like appName and appVersion, platform, userAgent if you have to do anything that's targeted specifically at a particular browser. You also have the ability to use the timing mechanisms that you're used to using. So, set interval or set timeout or clear interval or clear timeout. So if you have to do any sort of delayed processing within the worker, you can still do that using those APIs. And then like I've mentioned, you can do AJAX calls by calling the XmlHttpRequest object raw or if you have something that wraps that up you can do that as well. When it comes to browser support as you can see, well some of the browsers have been doing this for quite a while and then there's one guy who's a little late to the party. So Chrome, Firefox, and Safari have all supported web workers from about the 3-4 version of the browser. Opera 10.6 is where you'll find web workers. And unfortunately, even Internet Explorer 9 does not yet feature web workers. So, what you have to do is really kind of think hard about how you might want to use this technology. And if you're in a situation to where you can mitigate the problem of Internet Explorer not supporting web workers, then you may be able to begin using this today and hopefully even better, IE will soon support web workers. But all is not lost. Now, here's some links to some articles that you can read that give some ideas of ways that you can bring pseudo-threading into Internet Explorer. The approach is completely different than the way web workers work and it's not even true threading, there's no real thread that's being spawned, but it gives you an opportunity to architect your application in such a way that it might seem like threading is happening and you don't necessarily lock up the UI when you have some intense calculation happening. So, How to Process Large Volumes of Data in JavaScript and JavaScript Timer-Based Pseudo-Threading are two articles that you can check out and make some decisions. But in light of all that, let's go ahead and take a look at where the standard is right now and get started with some demos.
Demo: Fibonacci Sequence with No Worker
Working with the Fibonacci series is a great way to kind of push the envelope and tax the processor a little bit in order to have examples here for something that works well with web workers. Now if you're not familiar with the Fibonacci series, basically what you do is you start with the series of 0 and 1. And the series behaves as if you take the last two numbers in the series, add them together, and make that the next value in the series. So, 1+0 is 1, 1+1 is 2, 2+1 is 3, and so on. So, things tend to work fine if you want to do 5 of them or if you want to do 10 or even if you want to say, do 30 of them. So, you'll notice on this page, I'm not using any web workers and everything seems to be generally responding well. I have this animated .gif that's running in order to show you that the UI thread is continuing to respond and everything seems to be working just fine. However, what I'm going to do is go from generating a series of 30 numbers in that series to 40. So I'll hit Generate Series and the first thing that you'll notice is that the animated .gif stopped working and let me hit that again, so that stopped working, I can't select anything, and finally now that it's done generating it all the way down here, I can bring focus to the input textbox here. So, what's happening is is as the numbers are crunching in the background, the JavaScript is executing within the UI thread and it's completely hanging everything up. And so if I were to get crazy and make this a 45, I'll sit here and wait a little bit longer than I did for even a series of 40, and you'll notice that I can't scroll, I can't select anything, it's completely hung up and it'll stay that way until it's done generating all of the numbers for a series of 45 items. And in fact, just like you saw, I have this unresponsive script. And so what's happening is that the browser is noticing that this script is taking way too long to process and it's asking you do you want to wait for it or do you want to kill the pages. So in this instance, what I'll do is I will kill this page and then I get something like this, which really translates to something that's a pretty bad user experience. So, in order to avoid this, we can use web workers in order to do that same type of processing and what you'll notice is that I can go well beyond a series of 40 numbers in a Fibonacci series and the UI will continue to respond correctly and I certainly won't end up with anything like this. But before I show you the implementation with the web worker, I'd like to show you around through the non-web worker code first. So here's the page and we've just got some basic structure to the page, I've got my titles, I've got the input box that allows me to have the seriesLength, the generateButton, and then that animated .gif. And all I'm doing is using this ordered list in order to list each one of the items in the series. So to begin, the first thing that I do is create a results array. And then I also have this variable set aside in order to basically point to that unordered list, which I select using a jQuery selector right after the ready function. And so all of the meat of this is happening when I click on the generateButton. And so the first thing I do is just clear out the log list and after that I'll get out of the textbox the length of Fibonacci series that I'm looking to create. And then from there, I just run this code that's generateFibonacciSeries, which is a recursive procedure in order to continue to find each one of the values until I've hit the series length. I'll show you the implementation for that in just a moment, but once this runs in its entirety, it will fill up the results array with all the values that I need, and then what I can do is iterate over those results and then log each one of the items in the series to the unordered list. So calculating the Fibonacci series requires this procedure, and we'll get into the implementation details of these functions because it's kind of out of the scope of what we're talking about. What the value is I can take all of this processing and move it out of the page itself and bring it down into a web worker and then we'll see a dramatic change in the way the page behaves.
Demo: Fibonacci Sequence with Web Worker
With this sample, I'm doing the same exact thing, I'm generating the Fibonacci series, except this time I'm using a web worker instead of having the logic process within the UI thread. So, you'll notice a little change that I made to this item was that instead of having the animated .gif just kind of spin on and on, I've hidden it to begin with. And that's just because the previous sample I wanted you to see it spinning and then how it would stop moving, but to make this a little more real world, what I did was I made it so that I only show the animated .gif when it's actually thinking. So again, if we look at compared to the other one, if we generate 10, that's pretty fast, even quite a bit faster than before. If we generate 20, pretty darn fast. Okay, that's fine. We started to hit some problems when we were getting into a series of 40. So let's generate that series of 40. You notice I can still select, I can click within the box there. The animated .gif continued to run and now I have my series of 40. So what would happen if I made this 50. So I'll generate this series. Again, I can continue to do things within the browser window. I can click in the textbox, you'll see how the button background highlight changes, so as this continues to process the series, you'll notice that the page is just completely responsive, everything works. I wish you could hear my processor spinning right now, it's working overtime in order to generate the series. But I can assure you that even as this has been running, and it will run for quite some time in order to generate this series that I won't end up with any sort of unresponsive script errors. The processing will just kind of continue in the background working happily in its own little area and I can continue to work and interact with the UI thread just as if none of the processing was happening. So let's go ahead and take a look at the code involved in order to introduce the worker. So the structure for the page is exactly the same as what you saw before. I've got my textbox, my button, my little animated .gif, the difference happens to be is that now what I'm doing is working with the web worker instead of implementing that logic specifically within the browser. So here I've got my variable set aside for the unordered list, my load image, and then also the worker itself. So what we're most concerned about here is creating a variable for the worker. And then when we click on the generateButton, what's happening here is I'm showing the image and then I'm creating a new instance of a worker and I'm pointing it to a JavaScript file. And then I'm handling some events, so onmessage I'm going to process the messageHandler, and onerror I'll process the errorHandler, and then I'll post the message to the worker. So, the worker gets its commands by posting messages to the worker and the worker will send information back up to the main UI thread by posting messages back up to the window. So as a message comes back from the worker, what I'm expecting to get is an array of the values that are in the Fibonacci series. That comes in from the EventArgs under .data and those are my results, and then I'll just loop over those results and log each one of them into the unordered list. Just almost exactly like I've done before, but instead of it being a local array that exists within the window, this is an array that's passed in from the worker. And so once I've displayed all of that information up on the page, then I just hide the loading image, that little spinning animated .gif. And for the error handling, I'm just kind of punting here, if there's an error I'm just playing it off to the users. So depending on the types of errors that your application could encounter, you may want to handle those in a more robust way. For demonstration purposes that's all I'm doing. So that's the host page. Basically all I'm doing is working with the web worker in this way, instantiating it, handling the events, and posting messages to the worker. So, the worker is its own JavaScript file and in large part if you'll notice here I just simply copied the functions out of my other HTML page and pasted them in here. So it's the exact same code and you'll notice I've declared my results variable here at the top and the exact same code runs in the worker as it did on the page. The main difference is here is that the worker will register listening for the message event. And so when that message event fires, the messageHandler function will run. And as far as this demo's concerned, it's very, very basic. So as long as my data is greater than 0 and when I'm passing in here as the length of the Fibonacci series, I'm looking for a series that's greater than 0, then I pass that value down into the recursive function calls and I have the numbers being generated. So the last step in the operation is to post messages back up to the main UI thread. So, when I said I copied and pasted these functions in directly from the other HTML sample, that's true, except there is one change that I need to tell you about. So, here when I'm finally done calculating the series, if I call postMessage and pass in the results, that's the function that I need to call in order to communicate back up to the main UI thread. So by calling postMessage, then the message event will fire and then whatever I put in the EventArgs for postMessage is what will show up here in the EventArgs for data when the message event is handled up on the UI thread.
Demo: String and JSON Messages
Now I started with the Fibonacci sample because I wanted to give you an idea of the dramatic difference of what happens when you don't have a worker and when you do have a worker. This demo here is similar to the techniques that are used with the Fibonacci sample, except it's stripped down a lot because I want to make sure you have a really clear understanding of how the API works. So this demo, all I'm doing is posting messages from the host window into the worker, and then back again. So you'll see here when I click on that button, the worker says hello. I'm able to also log what's happening as it happens and basically over and over again. It's just interacting with the worker in order to do a hello world type of thing. The code is as you might expect, a lot like what you saw before. So we're instantiating the worker, we're handling onmessage, onerror, and then the main thing I want you to make sure that you have clear is that when you're communicating with the worker, you're calling postMessage and then the worker does the same. So you call postMessage in from the worker. And once again, addEventListener, looking for the message event, and then delegating off the control to this function and so as the messages come in, you can do it with strings, you can do it whatever. And this is obviously a very simplistic view of how things might work, but as your workers get more complex, you'll likely want to do more with them. So the next sample I have prepared for you uses JSON messages in order to do something that's a little more involved. So in the browser when I click on the Post Message button, you'll see that I have a message here that says your value is, and then 100. The difference here is that I have a JSON object that's responsible for doing a little more than just the string before. So here's the structure for the JSON object. I'm passing in a command and then I also have a Message. So this is the Message that's returned back from the worker after everything's been manipulated. So the input is Command and Value and what I get back is a Message. And you could completely separate it out as well if you want to also. You could have one JSON object for input and one for output, but I just wanted to keep it simple here. And so when I come down to the button click, again I'm instantiating a new Worker, handling the onmessage and onerror. And then with the arguments I'm saying Command is start, the input Value is 100, and then when I do post Message instead of sending in a string, I send in the JSON object. So now in my worker, doing the very same thing that I did before, addEventListener, I'm looking for message, and this will run this function here. So again, everything comes into the worker under the EventArgs through the data property. And at this point, once I'm looking at the data off the EventArgs, this is the instance of my JSON object. So I can simply say args.Command, if it equals start then I can give it a message, Your value is, and then I can read in the value from the JSON object. And then I can take that same JSON object and post it back up to the UI thread. So there's a distinction that I want to make sure that you have clear in your mind here. That when you post a message from the UI thread, you're taking this JSON object and you're sending it over to the worker. It does exactly that, it takes this JSON object and sends it down to it, but what it's doing is it's creating a copy of that JSON object. So what that means is that if you make a change over here in the worker, that change is not automatically reflected up in the instance of the JSON object up in the UI. So, the values that you're sending back and forth are copies of the objects. So you want to make sure you keep this in mind because let's say you're returning a large amount of data and you're sending it between the UI thread and the worker and back and forth. You need to make sure that you're handling your memory management and dealing with your variables the right way in order to protect your application from memory leaks. So it's up to you about how that implementation happens, but you do want to take great care of how these variables are handled if you get into scenarios where you're working with large amounts of data.
Demo: Ajax in a Worker
As I mentioned earlier in the module, one of the things that you can do within a worker is have access to XmlHttpRequest, which basically allows you to make AJAX calls within a worker. So on this page I have just exactly that setup. So I have just a regular web page and instead of making a typical AJAX call, I'm doing it from a worker and so when I click on this button you can see that the content comes in from an external page. And so to make that happen is actually quite simple. You'll notice here I have basically the same exact structure that I've had in most of the other demos. So I'm instantiating the worker, I'm setting up the EventListeners for message and error, and these functions down here are handling the events. So when the data comes in from the AJAX call and it's sent up from the worker, all I'm doing is taking the value that comes from the EventsArgs .data and injecting that into the HTML of a container that I've got on the page. So to kick things off, I call postMessage and pass in the argument of fetch. And so when we take a look at the worker, the messageHandler is run because I've setup the addEventListener to find out when the message comes in. I can take a look at the data and if that equals fetch then I can call fetchContent. From within fetchContent I'm just doing a typical type of AJAX call and this code may or may not be familiar to you. Many of us, and myself included, are often using libraries that wrap all this up for us, but it's good to get back to the basics and get down to the metal every once in a while. So I'm checking to see if we have XmlHttpRequest, that's for just about anyone of the browsers except for Internet Explorer, and if so, instantiate a new instance of that object. Otherwise, I have to new up a new ActiveXObject of Microsoft.XMLHTTP. Either way, I have an instance of the HttpRequest object and from there I can handle the onreadystatechange and if you remember from your AJAX basics, you have to make sure that the readyState is equal to 4 and the status is 200 and once you have both of those coinciding, then you have a response back from the asynchronous call. From there I can take a look at the xmlhttp, take the responseText, and post that back up to the host window. So that all happens once the response comes back, but in order to initiate the call to begin with, I call open from the xmlhttp object and the URL and then call the send function in order to initiate the call to being with. So just as you saw up in the browser window, the demo page I have setup here is quite basic, it's just a little bit of text wrapped in an h2, but all those pieces together illustrate how you have the ability, through a worker, to make AJAX calls quite easily.
Demo: Controlling Workers
With this demo, I'd like to show you some of the nuances that are involved when you want to try and control a worker. So to start, I'll kick off a generation here and then I'll send a message to the worker by saying hi. So you'll notice here a few things that have happened. First, I kicked off the Fibonacci sequence. It finished what it was doing before it was able to process another postMessage command. Because the way this worker is setup, it processed another postMessage after it finished the entire operation of generating the series. Depending on how you craft your workers, that doesn't necessarily have to be the case, but that's how it works for this example. Now if you want to control what's happening within your worker, there's a few things you need to understand. And first of all, that is you can't start a worker and then stop it once again. If you want to stop a worker from doing something, you have the ability to terminate it or close it. In either instance, if you want to start the worker again, you have to re-instantiate that worker and start it all over again. So the idea is that it's kind of, not a fire and forget, but once you get it going you can't turn the horses around and come back. So let me refresh the page to clear this out. I'll generate the series again and when I terminate, what you'll notice is that I have an immediate termination of the thread. So this just tells the browser, stop doing everything that you're doing and clear it out. And again, you have to re-instantiate the worker in order to do anything else again. If I hit Generate Series here again, the way I've set it up is to re-instantiate, but if I didn't, nothing would happen. So I'll generate a series and when I hit Close, what happens is is that when you hit Terminate, that just stops everything immediately. When you hit close, it gives the worker a chance to finish what it's doing, do some cleanup, and then return a response back up to the UI thread. So you can see here as opposed to Terminate, I have my series and then I also have a message that says closing the worker thread. Let's take a look at the code real quick so you can see what's involved here. So the structure for the page is I have my textbox that allows me to put in how long of a series I want to generate, my generateButton, the echoBox that allows me to type in the message, terminateButton, closeButton, and then my little animated .gif. So, what happens with the generateButton is I'm doing some cleanup here and then I'm creating a JSON object with some arguments to pass in to the worker. So if I come down here and you can see createNewArgs, I'm sending in a Command, the Value, and also a Message that's returned. Within each one of these functions I'm calling a function called getWorker. And again, because I always have to re-instantiate the worker in order to make things operate after it's been terminated or closed, I'm making sure that happens. So I have a global variable here of Worker, so if it equals null then I'll new up the Worker and then subscribe to my message and error events like I've done in the past. So, if I want to terminate the worker, all I simply need to do is call the terminate function from the worker itself and then everything ceases to operate immediately. If I want to close the worker, well the closing has to be done with inside the worker. So at this point what I'm doing is I'm creating the new arguments to pass in and I'm telling it that the command is close because if you take a look at the signature, I'm passing command, value, and message. The results that come back are the same implementation you've seen in the other demos, so I'm looping through each one of the items in the array, adding an item to that unordered list. But the real interesting part is now what's found within the worker itself. So, beginning from the start, adding EventListener for message and pointing to messageHandler. So the messageHandler is the entry point here. I can take a look at the arguments that come in and interrogate the command. If I'm starting, I'll just generate the FibonacciSeries like we've done in the past. If the Command is close, then from the worker I call this.close. So if the calculation has already been started, again it'll wait until it's done processing, then it will close everything up, clean up any variables, and move on. I am able to post a message back up to the UI thread and move on, but you are able to still post a message back up to the UI thread. And if I'm echoing some information, then all I'm doing here is basically just returning it back up to the UI thread. I'm creating a new JSON object with some arguments and that's just done here in the same way I sort of did before, I have a Message and a Result and then I postMessage there. So the main takeaway is that if you have a worker that's running and you need to stop execution immediately, you call terminate. If you want to stop execution of that worker after it's done processing a certain operation, you would need to call the close function from within the worker.
Summary
So you've seen the mechanics of web workers, but one of the things that you may still be wondering about is, well what exactly is a practical application for this type of functionality. And so I'm going to give you some ideas, but obviously it's not at all limited by what you see here, but here's some common scenarios that you might run into that could be valuable for you. So let's say you're building an application where you need to do some syntax highlighting within code. Splitting that off into a web worker may very well be a very good idea. Also, 3D rendering of graphics is something that's an obvious choice for using a web worker. So if you look up ray tracing on Wikipedia, you encounter this image, which is strikingly very realistic, but this is all generated by a computer. And it uses the ray tracing algorithms in order to generate it. Now, I don't know if a web browser in JavaScript could handle building something quite this detailed, but certainly if you wanted to attain to something like that, you may want to consider using something like a web worker in order to do that type of processing and that type of crunching. Certainly encryption algorithms and encrypting of data is perhaps the type of thing that you might want to split off and allow it to work outside of UI thread and then you could even do things like some very intense statistical analysis or financial analysis or any sort of number crunching. Again, anything that may take a long time to process. And the final practical application I'll give you here is the traditional chat application and having the opportunity for these messages to go back and forth outside the UI thread may be very, very attractive to you. So you've had an opportunity to see how workers bring threading to the browser. You now have the choice to split off these intensive types of operations in such a way that you won't hold up the UI thread and you'll be able to allow users to continue to work with the ultimate goal of creating a better user experience for the people who use your software. Workers are available in two different flavors, dedicated and shared workers, and their value really comes into play when you have intense processing that's required in order to make your application work. Although there's the restrictions of not being able to access the DOM in the parent window, the API is simple enough that I think it allows enough flexibility for you to do most of anything that you might want to accomplish. Well thanks again for joining me for Advanced HTML5 here on Pluralsight in this module on Web Workers. This is Craig Shoemaker, and I hope you join me for the rest of this course here on Pluralsight.
Fundamentals of HTML5 : Web Sockets
Introduction
Hello and welcome to Pluralsight's Advanced HTML5. This is Craig Shoemaker, and in this module, I'd like to introduce you to WebSockets. So of course I'll begin by defining exactly what WebSockets is, but there's a few things I'll need to cover in order for all that to make sense. So I'll review some traditional communication systems and what real-time data looked like before WebSockets. Then you'll see the advantages of WebSockets and then a contrast between the WebSockets framework and HTTP. Then before I get into the actual HTML portion of the demos, I'll give you a quick run through the server anatomy of a WebSocket server and then I'll show you how to connect to the server, we'll send some messages back and forth, and finish everything up with a stock ticker.
What are Web Sockets and Communication Formats
Starting with the question, what are WebSockets? Well the definition is that they're bidirectional, full duplex, client server communications available within the browser. Now, let's not just stop there. Let's take a couple steps back and see if we can kind of set the stage for what exactly that means. So if you look at communication methods, you have this whole idea of duplex and you half duplex communications and full duplex communications. The way to best think of a half-duplex communication is like a walkie-talkie. So if you're talking to someone using a walkie-talkie, when you press down the button on the walkie-talkie, you have started sending a message to the recipient on the walkie-talkie and you can't hear anything they're going to say. So when you press that button, you need to speak whatever you're going to say and then the parlance says that you say over, you wait for the response, and it comes back. So only a single direction of communication is allowed at one time and if you wanted to fake two-way communications, you basically have to have signals going back and forth between the two devices in rapid succession. So that's half duplex communications. Full duplex communications is when you have a connection going both ways at the same time. And this is what we're used to finding with modern cell phones. Well, HTTP basically works as a half-duplex communication and WebSockets, which not only is an instance of something that you create within your browser to communicate to the server, but also includes its own protocol and WebSocket frames to send back and forth. Instead of traditional HTTP headers, it is all included with the idea of what WebSockets is. So real-time data before WebSockets include AJAX and this thing called Comet. And you may or not be familiar with Comet because I guess if you come up with a new pattern on the web you have to name it after a cleaning supply. Well, actually there's more to it than that, because the idea of Comet is that it's either long polling or streaming. And so the way that the pattern works is that you make a connection to the server and with long polling you might be making numerous requests multiple times in the same way that you would have the same AJAX polling application. So polling just means that you make multiple requests in a short period of time in order to recognize any new data. Long polling includes polling except the server introduces a little bit of a delay before it sends a response in order to have an opportunity to gather more data before it sends a response. Well HTTP streaming consists of a connection that's made to the server, and then the server never really sending the end response command, so that a connection between the server and an individual client is kept open and data can be streamed. So long polling and streaming kind of fall within the realm of a pattern called Comet and obviously AJAX is many, many things, but that can include a number of different types of polling applications. So if you take a look at what happens between the client and the server between a polling type of architecture, is first you make a request and you get a response. And then you make another request and you get a response. And this is done perhaps indefinitely. But there's a lot of overhead that goes, just the pure metadata, the HTTP headers that go back and forth, when you're not even talking about data at this point, all that information is sent back and forth and it consumes bandwidth and it also consumes server resources, but it makes a big impact on not only the performance of the machines, but also has implications to really how real-time any data can be, because as soon as I make a request and then get a response back, a change could happen immediately on the server and until I make that next request to get the other response, I'm not really seeing the change. So even though you might be talking about seconds or even fractions of a second, there's still some latency that can be introduced into your architecture. The way sockets intend to work is that the client sends a request down to the server, a connection request, and obviously it gets a response, but then there's a connection that remains established between that client and server. So the server can continually send responses up to the client without having to require subsequent requests from the client. So once that connection is made, this diagram doesn't really show it, but obviously the client can send messages back to the server, but the server is able to keep communication with the client without having to have this back and forth, back and forth. And again, it has implications. What does that mean? Well we're saving bandwidth, we're saving server resources, and it gives an opportunity for anytime a change happens on the server for the client to be immediately updated.
Web Sockets vs. HTTP
Now the issue of header or metadata size becomes an issue very quickly because often if you're building an application where if you need real-time data or you need instantaneous communication between the client and the server, often those applications need to scale. And if you have a single request of information, with HTTP, which the HTTP header could be hundreds of bytes of information, and all of this is without data, but a socket transition would include just 2 bytes of data in order to frame that data. After the connection's been made, there's a dramatic difference between the amount of information that's going back and forth between a web browser and the server. Let me dig into this a little bit more for you. So, this is a typical HTTP request header. And you'll notice a lot of information is being sent down to the server. So we've got the host and MIME types that are accepted and how things are encoded and character sets and refers and the cookie that goes back and forth between the requests and all of this again, is sent whether or not you're sending 1 byte of data or thousands of bytes of actual data. So that's what's sent to the server. The response then gets sent up from the server and saying, okay this is the type of server I have and this is the content length and here's the date and all this information. So all of this data is transmitted via HTTP with every single request that goes to and from the server. What happens with WebSockets is there's an initial request down to the server, but if you'll notice, that protocol is upgraded to the WebSocket protocol. And again, once a connection is made from a browser to a WebSocket server, that connectin is maintained and then data sent on subsequent requests that data is framed by only 2 bytes significantly reducing the amount of overhead that's involved in order to facilitate communications. So here is a graph that I got off of websocket.org/quantum.html. And this basically shows again, the effects of scaling, say if you were looking at doing a polling application over WebSockets. So over on the left hand side you see the bits per seconds and on the X axis what you're seeing here is the amount of overhead that's sent between requests. With Use Case A, if there's a thousand clients connected to the server, with Use Case B, if there's 10,000 clients connected to the server, and in Use Case C if there's 100,000 clients connected to the server, the amount of overhead required in order to create a polling application where it's polling once a second is astronomical. Yet when you look at the amount of data that's sent through WebSockets, from this graph at least there's barely a perceivable difference. Obviously the amount of data is different, but since that overhead is not there, that makes a huge difference on how these applications can perform. Now I want to make sure I give credit where credit is due. Many of the graphs and some of the header information that you saw here within this module is available to you through websockets.org/quantum. And this article, A Quantum Leap in Scalability for the Web goes into many of the technical nuances of some of the information that I've shown you and I suggest that you check it out. Peter Lubbers is also the lead author for Pro HTML5 Programming from Apress as well. And Kaazing is known for its WebSocket implementation and in fact being a very significant contributor to the HTML5 spec.
Browser Support
Looking at the landscape for browser support is a little bit different in this case than it is with other APIs. First of all, you can see that while at varying versions, each browser supports WebSockets, except for Android, but Firefox and Opera are designated as having partial support. So while Chrome, Safari, and IE support WebSockets out of the box, you just need to make sure that you're running the right version of those browsers. And for IE, support starts at version 10, so there's a lot of upgrading required on the user's part before IE support is considered ubiquitous. Now partial support means that the current WebSocket protocol supported in the browser has a known security flaw and therefore the WebSocket API is disabled by default. Users can manually enable WebSockets, but this must be done on a user by user basis. This table depicts the different WebSocket protocols and the latest version being RFC 6455 as the most stable protocol and will eventually serve as the basis for the most secure protocol of choice. And you can see that it's the latest version of each browser, except Android, which includes support for the RFC protocol. Notice also that the footnote that points out Gecko-based browsers must access the WebSocket class as MozWebSocket, which you'll see in the coming demos. So if you want to test your applications in Firefox or Opera, you'll have to enable WebSocket support explicitly. So in Firefox, you navigate to about:config and this brings you to the configuration screen for everything in the browser. Then filter on network.websocket and you'll notice that network.websocket.enabled defaults to true, but network.websocket.override-security-block is set to false by default. To make the required change, you just need to double-click on that item and the value will update to true and now you'll be able to use WebSockets in Firefox. Now Opera is a little bit different. If you navigate to config#UserPrefs|EnableWebSockets, it will take you to the User Preferences of the browser and bring focus to the enabled WebSockets option. At that point you just need to click on the checkbox and then click to save changes at the bottom of the page, and now you're able to use the API in Opera.
Demo: Introducing the 'Hello Server'
Before I dive right into the code, I'd like to introduce you to Fleck. Fleck is a server-side implementation of a WebSocket server that I use in the following demos. Now it's written in .NET, but by no means is .NET a required server implementation in order to use WebSockets. In fact, if you take a look over at the Wikipedia page for WebSockets, you can see that there are a number of different types of server-side implementations available for WebSockets. I happen to be using one in .NET because that's where I'm the most comfortable, but depending on where you're the most comfortable, you'll surely be able to find a current implementation that should suit your liking. Alright, now I wanted to show you the overview of the running sample so you can see how the WebSockets work between the server and the client. So here I have the socket server running as a console application. At this point, I can choose whether or not I want to run the Hello World Server or the Stocks Server. I'll go ahead and press 1 and start the Hello World Server. You can see that the server is starting and it's exposed through the location of the localhost, port 8181 using the WebSocket protocol. Now, let's go to the Web page that uses the server. So the first thing you'll notice is that it's attempting to connect to the server and now a connection is opened. From here, I have two-way communication between the client and server. So let's type a message from the server to go up to the client. Hello from server! You'll see as soon as I hit enter, the message is received up on the client. Now it goes both ways. So if I wanted to send a message down to the server, I can do the same thing. Hello from client! Now what I've done is automatically echoed any messages that go to the server back up to the client, so you'll see server says: client says: hello from client! And down here, client says: hello from client! So I have this two way communication established with the server. Now, I can also add other clients to the mix as well. So you'll see that the connection to the server, connection is opened, you'll see down here connection is open. So I can say, hey guys! And so here on this tab I get hey guys and on this tab I also get hey guys! So the server maintains a list of all the connected clients and then it's up to you whether you want to send them to all of them or only specific ones, that's an implementation detail on your part. But all the connected clients can get messages from the server. So, I can continue to do this, or if I just tell it that I want to exit out of the server, you'll see that the connection is closed here on this tab, as well as on this tab. Alright, well let me show you the code for how this all works.
Demo: Exploring the 'Hello Server'
So, starting with the HTML page, you can see that the first thing I have is an input element that allows me to type in the message that'll go down to the server. Then I have an unordered list that acts as the log. So as I interact with the server, new list items will be added into this unordered list element. I'm working everything off of the jQuery ready function and the first thing I define here is a function that allows me to log items within that unordered list. So, here you can see I pass in a message and it creates a new list item within that message. Now just like I showed you within the slides, depending on what browser's being run, the Gecko-based browsers need to find the WebSocket class under window.MozWebSocket. All other browsers will find it under window.WebSocket. So, depending on whichever one is appropriate for this browser, I have referenced that class and I can instantiate a new instance of the WebSocket class saying that I'll be accessing the server through ws://localhost through port 8181. The first thing I'll do is log that I'm Attempting to connect to the server. Then when the socket is opened, the onopen event will fire and I'll log that the Connection is opened. I'll do the same thing when it's closed. As messages come from the server to the client, the onmessage event will fire. When this function is run, I'll have the EventArgs available here and I want to look at the data property on my EventArgs. From there, I'll have a string that's returned from the server in order to print out on the client. Should an error happen, I'll handle it here at this point, and if I want to send a message down to the server, here I'm handling the change event of my textbox, but when I have a value that I want to send down to the server against the WebSocket, I just call the Send method, passing in the string value that I want to send down to the server. So, when I want to send a message to the server, from the WebSocket I'm calling send and when I want to receive a message from the server, from the WebSocket I'm handling the onmessage event. Alright, let's take a look at the server implementation now. Now just as I showed you during the running demo, this server exists as a console application. So here this is just a standard .NET console application, I've got the Program and the main running routine of it works right in here. I print up the messages to the console user to say which server do you want it to run, and from that point I tell it that based off of an entry of 1, I want it to run the Hello Server. The next demo I'll get into the Stocks Server, but for right now let's see how the Hello Server works. Once the Hello Server is told to start, then I create a couple variables here. The first one is the list of sockets. So you'll notice I create a list of IWebSocketConnection, so every time a new connection is made from a client, a new entry is added into this list. And then I have a variable specifically for the server itself. So as I instantiate a new WebSocketServer, I say that it's available under ws://localhost, port 8181. So now I'll go ahead and start the server itself. When a connection is opened, the OnOpen event is fired and at that point I can take the incoming socket and add it to the list of all sockets. Here I'm just telling the console that the connection is open. I do basically the same thing for close except I take the socket connection when it's closed and remove it from the list. And then when a message is incoming from one of the connected clients, the OnMessage event fires. And at this point, I'm just choosing to take each one of the sockets in the list for each one of them, I'm taking that individual socket, and I'm sending up the message back to that connected client. So basically I'm just echoing back any input that comes from one of the connected clients. Now on the server end, I'll grab any entry that's come in from the console and as long as that doesn't equal the string of exit, then I'll send that same input string up to all the connected clients. So taking the list for each item in that list, I'll go to the individual socket and send the input up to that client. So that all continues to work until you type the exit command and then at that point the server closes.
Demo: Implementing a Stock Ticker
Now this next demo implements a very basic stock ticker. You'll notice here that the data is coming in using WebSockets in sort of a real-time fashion. Now, the data that I'm using is just dummy data, it's generated by a utility that I'll show you when we get into the code, but for all intents and purposes, this works just like you'd expect any sort of regular stock ticker. So, if the value is up, it's colored in green through a CSS class. If the stock is down, it's colored in red, also through a CSS class. So you'll notice that the page here attempted to connect to the socket server, and then connection is opened. But when we look down in the server, you can see that the connection has been opened actually three other times. So, if I bring Safari in here, you'll notice that the data that's being broadcast to Safari is exactly the same as it is to Chrome. These are just two different connections that are coming in from two different clients. The same is available if I bring in Firefox. Again, we're at number 77, 78, and on and on, and also the very exact same thing for Opera. So as you can see, all the different clients can be connected to the server, and in this case, the clients happen to be completely different web browsers. So let's begin with the HTML for this sample. There's a few classes here within the CSS that you need to be aware of, and that's the up and down classes. So, if the stock is coming up as being up, then it's colored green. If the stock is down for the day, then it's colored red. As we take a look down into the elements, the HTML elements, you'll see that I have a log here, which is basically the activity log, it's the same thing that I had in the other sample, and then I have another unordered list, which handles the stocks. So this is my real rudimentary stock ticker. In JavaScript, I'm using jQuery to handle the ready function and then I have the log function, which is exactly like the one I used in the last demo. It basically just creates a new list item element in the unordered list in order to handle the activity log. Then I create this variable stocks. And based off of this selector, it's going against the unordered list with the ID of stocks. So every time a new stock needs to be added into the list, the function is wrong. There's a JSON object that comes in as stock, which is added in as an argument, and the first thing I do is look to see whether it's up or down for the day. If it's up, it gets the up class, if not it gets the down class. So if it's up, its colored green, if it's down, its colored red. Then based off of my unordered list, I prepend and item each time I have a new one. So this makes sure that the new stocks show up at the top of the list. Then I create a new list item and add the class that I came up with here from looking at the IsUp property. Then I can pass in the Symbol, in this case I'm just switching it to uppercase, the Value, and the PercentChange from each one of the stock objects that comes in from the server. Then I log that I'm attempting to connect to the socket server and then just like I did before, if I'm in a Gecko-based browser, I need to instantiate the class of WebSocket through the MozWebSocket class. If it's not Gecko, then I can go at it just from WebSocket. Once I have the implementation that I need, I can instantiate a new instance of webSocket and say that I'm accessing it through ws://localhost:8181. When the connection is opened, I'm just logging saying that the connection is open and same with closed. Now, with onmessage, the incoming message from the server, I'm able to look at the EventArgs and find the data as a part of that EventArgs. This comes in as a string and what I really want is the full JSON object. So I'm telling JSON to parse it and now I have a full JSON object. From there, I can take that stock and run the addStock function in order to add a new stock into the list each time I get a message from the server. Now before I get into the specifics of the stock server, I want to review at a high level what's happening. In order to setup the Stock Server, the first thing that I'll do is create a list of stocks. I'll use a utility that generates arbitrary data and it'll put it within this list here. So this acts as the sample data that's used within the demo. Then I've got a timer that's set to go off every second and a half. So every time that timer ticks it'll send new stock information up using the WebSocket to the connected clients. So I've got my timer here, my list of stocks, and also the list of sockets. So as each new socket connection is open, that socket is added into this list. And then I just have an index here, which is used to keep track of which one of the stocks I'm sending up. So as the server is started, the first thing I do is create a new instance of the WebSocketServer. Again, available under localhost, port 8181 using the WebSocket protocol. The program then starts the server and then each time a connection is made, an OnOpen event fires and I add that socket to the list and each time a connection is closed, I remove the socket from the list. Then I use NBuilder, which is a nice utility that creates collections of objects with arbitrary data in it. Here, I'm creating 1000 instances of the Stock class. To get an idea of what's happening inside the Stock class, you can see I've got the Symbol, Value, IsUp, and PercentChange. That's exactly what you saw represented by the JSON object that I used up in the client. So I create 1000 instances of the Stock class and add it to that list and then setup the timer. So every second and a half, the timer ticks and it calls SendStock. And then here I'm just printing up the message saying that I'm sending stock info to all the connected clients. This ReadLine here is a .NET way of saying within a console application to wait for some sort of response. In this case, I don't need to take any other commands because I'm using the sample data to send up to the clients. So pressing any key basically would stop the server. Then lastly, the method that's used to send stock information up to the clients is right here, and I've started off with a serializer. So as I have a full domain object available, I need to serialize that down to a string so I can send it up to the client. So that's exactly what's happening here. I create a new instance of the JavaScriptSerializer, I serialize the specific one that I'm looking at. So here I look at the stocks collection and based off the current index that I'm at, I pull out the individual stock that needs to be sent up to the client. Once that's serialized down to a string, then I take the list of the sockets and for each item in that list on each socket itself, I send the message up to the connected client. Then after that, I increment the index so the next time this ticks it'll go to the next one in the collection. And then here I've got some housecleaning code just to make sure I stay within the bounds of the collection that I created. So there's many different approaches you can implement when you're creating a WebSocket server. Here I'm not requiring any input on the server side, it's just all taken from data in the system and being sent up to the clients. So from here you can take this same approach and create a chat application, create a stock ticker, create any sort of bidirectional communication between the server and the client that uses WebSockets.
Summary
Well you've been able to see now with HTML5 and WebSockets that bidirectional, full duplex client/server communication channels are now available. And that comes with some pretty significant implications, because there's much less overhead endured with WebSockets than there is with HTTP. Now the browser support is kind of varied. Although many of the browsers do support it, a few of them you do have to enable WebSockets in order to make them work and that's not really a long term solution asking everyone to enable them. But hopefully soon each one of those browser vendors will get the security concerns that they have about WebSockets figured out and have it enabled by default. But the bottom line is, with a simple API you have the foundation you need to create some pretty amazing applications with WebSockets. Well this is Craig Shoemaker. Thank you once again for joining me here for Pluralsight's Advanced HTML5 and I hope you have an opportunity to join me for the rest of the series here on Pluralsight.
Fundamentals of HTML5 : Microdata
Introduction
Hello and welcome back to Pluralsight's Advanced HTML5. This is Craig Shoemaker, and in this module I'd like to discuss with you Microdata. To kick things off, I'll talk about exactly what is microdata and how it effects your markup in HTML. And in fact, I'll answer the question of what are the implications for existing markup that you may already be working with. I'll introduce the data vocabulary and then dig into the anatomy of the microdata format. We'll stop and take a look at the browser support, and then I have some demos available for you so you can see how microdata works its way into some more or less real life type of pages.
What is Microdata
Well what is microdata? Technically it's standard HTML markup married with a data vocabulary namespace. Now, before I get into the technicalities of what exactly that means, let's start with an example. So consider a regular Web page out on the internet from, I don't know, a company like Pluralsight. And if you take a look at the URL, it's Pluralsight-training.net/microsoft/contact.aspx. This is a real page that lives out on the web. And this page is suited for a human, for a user perfectly. It has a nice style sheet applied to it, it's serving in some graphics, and everything's presented and tuned for a human who wants to consume this information and interact with it as well. And this is the pattern used throughout the web in order to deal with humans. If you wanted to take that same information and expose it and make it available for a machine, well then you'd create some sort of a service. And so this service, perhaps, could be found at Pluralsight-training.net/ ContactService.asmx/GetContactInfo. Now, it doesn't. If you notice in the screenshot, the URL is localhost, so this page actually does not exist, I contrived it in order to make a point here. But, if Pluralsight decided to create a web service that would return contact information so that machines could easily extract this information out from the website, they could very easily do it. But the point I want to make is right now when we're interacting with users, we have one format, we have one page, and that's usually an HTML page with some JavaScript and style sheets and images. And when we interact with machines, we strip all that away and basically deal with an XML interaction, or JSON, or whatever the case may be, they're two separate avenues. Well what if, you were able to take the exact same page and make it available to both humans and machines. So if Pluralsight updated their contact page in order to deal with the fact that they're an organization, then when I use my web browser and went to this page, I would see something like this, but at the same time if some sort of machine using a specific API went to the exact same page, was able to extract out information that's useful to it in a format that it can understand, this is exactly what microdata is.
Data Vocabulary
Alright, well to take it a step further, here's a contact page of mine that just has biographical information about me and for some reason a gargantuan picture of me and links to social networks and blogs and things of that nature, but this is about what it would look like if you looked at it through a web browser. But let's look at the underlying HTML for a moment. At first glance, there's nothing here that's really all that interesting or groundbreaking, but if you look a little bit closer, you'll notice that there's some new HTML attributes and values that are sprinkled in with existing HTML that you may not have seen before. And what's particularly interesting is that if you look at itemtype, you'll see that there's a URL pointing to data-vocabulary.org/Person. And this kind of might feel like to you like an XML namespace when we're dealing with XHTML and it's similar to that. And the idea is, what we're doing is we're introducing a namespace or some sort of interface into the HTML in order to be able to define an entity that's outside the scope of this HTML. So let's take a look at what that person definition is. So this is from data-vocabulary.org/Person, and again, the whole point is to attempt to model a person. So you get the name, the nickname, image link, title, role, on and on, all the information about a person. So by having this information predefined and available, now what we can do is use that within an HTML page in order to again, model that information to a machine when it comes and reads this HTML page as opposed to a person to where they're just looking at the aesthetic and functional features of an HTML page. So where this is all going is that an API that you can use in order to test what your microdata looks like is a Google webmaster tools, Rich Snippet Testing Tool. And I'll take you to the URL and we'll do some experimentation with that in a moment. But you'll notice that I pointed this tool to the exact same page I showed you in the last slides and here it was able to extract out obviously the URL, the fact that I was from Corona, California, my title as Product Guidance Manager. If you look down here towards the bottom, you can see the URL for my photo, the URL for the company that I work for, my affiliation, which is Infragistics, and so that single page not only models a person, but also models an address. And there are many different types of models that you can apply to your pages in order to allow the extraction of that information.
Vocabulary Anatomy
Now let's take a look at the basic building blocks of a microdata definition. So what I'll show you here is applicable to any type of microdata of data vocabulary where there is a person or organization or an event, rating, doesn't matter, these are the basic building blocks that you need to know in order to introduce a microdata vocabulary into your page. So the first item is itemscope, and what itemscope does is it basically creates a container, it creates a group saying that within the structure of this container, so in this case, everything within this div, the ID container, that div, everything within that HTML element is scoped together to be related information. Now how that information is related is defined by the itemtype. So, I'm defining here by saying that the itemscope or group is created, the itemtype happens to be found at data-vocabulary.org/Person. So this defines this group as saying that there's person information found within this container. Now they can be nested. And if you'll notice down here at the bottom that I have another itemscope and another itemtype and then I'm pointing that to data-vocabulary.org/Address. So this person contains information also about an address. So the itemtype is the URL that identifies the scope. Now the itemprop is the attribute that you'll use in order to flag specific pieces of information within your markup. So once you define exactly what you're trying to describe, let's say a person, then you need to go through and say okay, each one of the attributes about that person is assigned somewhere within the data. And if you remember the table that I showed you before, so the definition of a person had a name, a nickname, title, things of that nature, that's exactly what's going on here. So again, I have a regular plain HTML markup like you'd just see on any other Web page and all I've done is introduce itemprop equals name, and then you have my name there. And so, when I'm looking at it in h2 or if I'm looking at a span, if I'm looking at most general types of elements, it'll just simply take the text value that's within that element. So everything that's between the tags, if I mark this as itemprop equals name, it knows okay, I've found this element, it's marked as the name, and I'll just take the text that's within the tags. But if you're dealing with a different type of element, it may not take the text, it might automatically take something else. So for instance here, I'm inciting itemprop as the photo within this definition of a person, but since it's looking at an image tag, instead of taking the text because there's really nothing, this is a self-closing tag, it knows that it will take the source. And so you need to be careful when you're working with this because, for instance, an anchor will take the href if you assign an itemprop to it, but if you put text between the opening and close tag of an anchor, you might expect that text to show up, but it will not because the href of an anchor is automatically extracted when the data is read through microdata. And so there's different kinds of these and I have a table at the end that shows you all of them, but if you assign an itemprop to a time element, what's extracted is the datetime. So there's some conventions that are established for you that make working with microdata not only reliable, but easier on you as well. The itemid attribute allows you to uniquely identify an item within your markup. So, this could be a product ID for a person, maybe it could be an Email address, for a book perhaps it's the ISBN number, it's just some sort of piece of information that works as a unique identifier for whatever item you're trying to describe. And lastly, itemref is the attribute that you'll use if you want to say, well I've defined a group through my itemscope as describing something in microdata, but my HTML doesn't play nice. And this property really drives home the point that this is meant to supplement existing HTML that you already have. It's not trying to create a new language for you, it's not trying to make you conform to its standard, it's really trying to figure out a way in order to extract this information and make it available within existing markup. The value of itemref is that if you have information that pertains to the data that you're describing through the itemscope and the itemtype, but it doesn't logically live within the same container of where you defined your itemscope, so perhaps most of your information is in that container, but you just have other stuff that's in a table somewhere and you need to relate those two together, well that's exactly the example that I'll show you of how it works. Itemref will allow you to point to a list of element IDs that are on that page that also contain information that is relevant to the itemscope. So you'll notice here I have information in a table and each of those IDs are space-separated within the itemref and so when the API reads this information, it knows okay, I have an itemscope, based on the itemtype I know it's a person, all my information about this person will be in this div except for, oh yeah, I need to go over and find the elements with these IDs and pull that information in for processing as well. So like I mentioned before, most every element that you work with will have its text content returned when you assign an itemprop to it. There are a few exceptions though, and this table lists each of them. So if you're dealing with a Meta element instead of text because there really is no text, it'll automatically pull up the content. Audio, imbed, iframe, image, source, and video all have their source attributes returned when you assign them as an itemprop. When you're dealing with an anchor tag, an area or link, all of those have their href returned, an object data is returned, and as I showed you with the time element, datetime is a value that's returned when that information is read through a microdata API.
Browser Support
When we talk about browser support, it's kind of different than just about any other of the technologies that we've discussed within this course, because the browser doesn't really have anything to support. What microdata is is markup that's sprinkled within existing markup, but there's no JavaScript API within the browser, there's no special rendering that it has to do in order to create a new form element, there's really nothing for the browser itself to do. Again, coming back to the magic of the HTML5 DOCTYPE, if a browser does not understand any of the markup that's found, sprinkled in, this itemscope or item property, again, it'll default a quirks mode and it'll simply ignore it. So browsers kind of deal with all this information silently because what you're doing is you're just taking a regular HTML file and you're formatting the data in such a way that a machine can read that same information. So, browser support here is really not an issue.
Demo: Modeling a Person
Okay, let's dive in to the nuts and bolts a little bit here. Now, by now the definition of a person should seem somewhat familiar to you a little bit. So if I'm defining a person, again I've got name, nickname, image link, the title, URL, affiliation with like what organization does that person belong to, and then you have the ability to identify social relationships between different types of people if you're linking to other people. So this is what a person is modeled like. And address I modeled like, well street address, locality, region, postal code, and country name. So again, the page that I've created for a person looks like this and this is up on the web so if you want to test how this works without having to create your own pages, you can go to polymorphicpodcast.com/microdata/person.htm. And so this is my gargantuan head page, and the markup for this page looks like this. So again, just regular HTML. I have a div, id container, I'm using this in my Stylesheet in order to mark it up and make it look pretty, and then I introduce an itemscope, so saying that everything within this container right here is related somehow to what's found in the itemtype of person, data-vocabulary.org/Person. And I have my h1 and then for the actual name that I want extracted out, I look at the h2 and assign the itemprop of name to that h2. So, the next itemprop is found within my image. And so I'm assigning this as the photo. And again, what's automatically return, since this is an image tag, is the source attribute of this element. And then you can see that my title, Product Guidance Manager for Infragistics, the URL comes in here. Now remember, this is what I told you about you had to be careful of when you're dealing with some of these elements that automatically give you a value. So if I had set itemprop affiliation to this anchor tag, just simply because the text value here is Infragistics, well it wouldn't pull out the text of Infragistics even though I've set it as affiliation, it would automatically go to href. So in order to make this work the way I want it to is that the URL needs to be assigned to the href and then I've just nested a span tag within my href to say well, my affiliation is Infragistics. So that way when the data is extracted out, it knows to get the right information at the right time. Then, the next thing I'm doing is assigning my address and I have a nested itemscope here, itemtype again of Address, and so the other point that I want to make here is the fact that just because all the definition information is available, you can model an address giving street address and everything on down the line, you have the option of providing as much or as little detail as you wish. So once you've set all this up on a page, how will you test to know that you've done it right? Well, Google helps us out with that and if you go to google.com/webmasters, tools, and then rich snippets, you have the Rick Snippet Testing Tool, which is in beta, which everything that Google has is in beta for a long time. And so all you need to do is paste in the URL of a page that has some microdata information in it. And this testing tool will read out the information about what you're defining, it'll automatically detect what's going on and return information to you. So, when I run it on that page that I just showed you, polymorphicpodcast.com/microdata/person, again it's like the slide that I showed you before. And so it gives me the name, the photo, title, URL, affiliation, address, all that good stuff by doing nothing more than adding just a little bit of extra HTML to a page that already existed.
Demo: Modeling a Product
The next type for your review is a product, and a product often comes with an offer. So let's take a look at both of those. So with your product you have the brand and category, description name, basically all the information that you're used to exposing through say an ecommerce application or if you're defining a product on a Web page, it's all modeled here within what a product is. Now an offer has the information about the price. So you have price, you can specify the currency, how long that price is good for, you can point to a person to say who the seller is, what kind of condition, availability, offer a URL, all that good stuff. So here is my product. It's the Star Wars Death Star Cookie Jar, because every home is in need of one of these. And so you'll see it's just the basic information like you'd see on just about any other product page. Again though, it's opened up through microdata. So if I take a look at it through the Rich Snippets Testing Tool, you can see that I'm pulling out the ID of the product, the type here says that I have a product, the brand is Star Wars, name is Death Star Cookie Jar, category, on and on and on. But beyond just defining a product, I'm also defining the offer, so you can see it's in U.S. dollars, the price here, and valid until the end of the year, new, in stock, and all the pricing information about the product. And also, organization information about the company that provides this. So if you want to buy this for real, you want to head over to thinkgeek.com and pick up that cookie jar. Well, the markup is much like what you'd expect. So I have itemscope, itemtype pointing to product and then itemid like I showed you in the slides pointing to the product ID. And again, itemprop for brand, name, and then category that defines the hierarchical category found for the product itself. I have my image defined here through itemprop of image and then description. Identifier is part of the product definition. The identifier itemprop, the content for this is a unique identifier as well. So this could be a SKU number, here it's a manufacturers part number, again it could be an ISBN number, it gives you another way to uniquely identify what's here on the page. Then as we come down in here, so I have Price information on the page and then I've defined a new itemscope saying that within this container here, I'm looking at an offer. And notice that the container for this isn't even a div, it's just a span. So I have currency defined and the content there is U.S. dollars. And you'll notice this is a meta tag and because really this is just metadata information that I'm providing. On this page, I'm not displaying it to the user, which I absolutely could, but for here I chose to use this approach so you could see how you could use it if you do want to hide it visually. And then I have price, priceValidUntil, and then I have a datetime value available, condition, content is new, availability, content is in stock, and then I have another itemscope available for the seller, so I've defined this as an organization and from within the organization I have a URL and a name. So that's just one way that you could model a product on your website.
Demo: Modeling an Event and Organization
Well in real life stuff happens, and for us, we use the web to tell everybody that stuff happens. So, here I have the definition of an event and it has all the information that you might need in order to not only describe, but also locate an event, summary, URL, location, description, dates, all that information. Well the example that I'll show you will define an event, but it also defines an organization because usually, organizations, companies are the people who put on an event. So, for the organization I'll be looking at the name, URL, address, telephone number, geo coordinates, all that good stuff. So this is our event, we have the Winter Concert Series. Beethoven is playing in person and this would be in February, only an hour, at Carnegie Hall, it seemed like the best place for it. You can buy tickets, all kinds of good stuff. You can tell I made these examples up when it was late at night. So, the markup for it here, again, itemtype of event narrowing it down to that, and then so we have the eventType and so I'm saying this just is a concert. So what's interesting is that within the title I say it's our concert series, but I can narrow down the event type to simply a concert just by sprinkling in this span right here. The summary here could probably be a little more verbose than just the title of who's playing, but I wanted to keep it simple here, and then you'll notice here I have the URL, and again it's within an anchor tag so it automatically pulls out the href. And the same thing for our photo, this will automatically pull out the source. I have my description within a paragraph tag, it just takes everything between the paragraphs. And then I have my date information, startDate and endDate and it's pulling out the full datetime information. And this format gives precision down to adjustments for time zone. So for the event when I'm describing the location, now I'm narrowing it down even further to saying that the itemtype, the location is at an organization's physical place. So, the organization, I give it a name, URL, address, so now I'm nesting even one more time, so that organization has an address, and then giving it a street address, locality, region, postal code. Now if I want to expose out the geographic coordinates of our location, I can do that here. I could show this on the Web page, that's fine. I chose to do it with meta information because there wasn't really anything interesting visually I wanted to do with it, but the Rich Snippets Tool and any other API that takes a look at this will extract the data out and then can do something interesting with it. So here within the geotag, and I forgot to bring up the definition for the geotag and I'll do that in a moment, we have latitude and longitude available. Further down, I even have an offer, which we've gone over before, and this is the information about the ticket price. So then we've got some of the elements that you saw within the last demo also available here all within this one page. So again, I want you to see that you have flexibility available to you, microdata data vocabularies are setup in such a way to be able to be abstract enough to define or describe just about anything that you're working with, and the way you format it and the way that you allow them to interact on the page is completely up to you. So like I said, I wanted to show you what the definition of the geo definition looks like, and so it's pretty basic. You have latitude, longitude, and item reviewed. So within the Rich Snippets Tool, if I take a look at that same URL and so you can see the same information is showing up here on the tool. Now you'll see this a lot. And the reason that, again they can't show the excerpt, is because Google will take a different piece of your page and return it as the description in the search results based off the keywords the users put in the search. So, the page will return, but if they searched, say for Beethoven or something, it might show up in this area or if they were looking for things about Carnegie Hall, it might extract information about Carnegie Hall and put it in the description here. But either way, the actual information that I marked up within the page is all available right here. So, when I'm looking at the events, again I have the type and the summary, URL, everything that I showed there, dates, and then also showed that it had a related information of the location and the ticket. So, this would be an organization and this would be an offer. So here's my organization, it's at Carnegie Hall. Now, for technical reasons I had to put this as polymorphicpodcast.com so it would validate, because when you're defining an organization, the URL has to be the same one of the web server that it's hosted on. So when I had carnegiehall.com on there, I had some validation errors. So that's a little contrived, but you'll get it when you work on it in real life. So then we have the address, all the address information for Carnegie Hall, the geo information, these are the real latitude and longitude coordinates for Carnegie Hall. I've got a couple offers available on the page, there's basically the early bird offer and then you have the latecomers offer that's available. So everything on that page is all exposed up through the microdata attributes.
Demo: Modeling an Individual and Aggregate Review
The next type I have available for you is a review. And so this could tie together very well with products, or even restaurants or organizations, things of that nature, but it's the whole notion of representing review data that's available on the web. And there's two types of reviews. There's an individual review and there's an aggregate review. So let's take a look at the individual one first. So we're pointing to the itemreviewed, we talk about the rating, we're able to define the reviewer, the date, description, summary, all that information that's available. So my review page looks like this. So Senior Peppers is an excellent grill that my wife and I have been going to since before we were married and obviously we love the food there, we love the people, it gets a five star rating. So, when we take a look at this page through the Rich Snippets Tools, you can see that it was reviewed by Craig Shoemaker on this date, it's been given a five star rating, and here's some of the other information that's extracted out. All this information is exposed using itemprop. I think you're getting kind of used to seeing that, so now I'll move on to showing you the aggregate review. The aggregate review represents basically a community of reviews. So if you have a website where in a visual, users can review a blog post or an article or a product, what you might want to do is expose, well the aggregate of all those reviews up in a certain way. So again, you've got the itemreviewed, which is basically the title of the item and then we'll point to an individual rating, get count and votes, and a summary. So my aggregate review looks like this, a bunch of people tend to like the Death Star Cooke Jar. It got an average of 9 stars out of 10 based off of 24 ratings and the count of the user reviews is 24. When we take a look at it through the Rich Snippet Testing Tool, you can see that, well I've got my ratings here, 9/10 from 24 users, I've got an image, all kinds of good stuff there. And then you'll see that I have the review aggregate and also with the rating that's available. So let's take a look at the code for this one just because I've got some nesting going on here. So again, I've got the itemtype as aggregate, item reviewed is from the h2 tag, the photos from the image, and then I've got a span that narrows it down to the actual rating and then I have my average and best rating that's exposed up. And I have the number of votes and also exposing that through the count of the aggregate review.
Demo: Relating Content
So there's dozens of different vocabulary types that you could use in order to represent data on your website, but I think by now you're getting an idea of how to set everything up appropriately if you know the type that you're working with. So the last example I'd like to show you here is how to use itemref. So again, back to the contact page, and like I said earlier, what I wanted to do was show you how to include microdata information that's within HTML elements that are outside of your itemscope. So, if you have data that's sprinkled around on your page and not exactly in a single container, this is what you want to work for you. So just like we've had before, itemscope, itemtype, this is a person. And then right at the top where I'm defining my scope, I say itemref. And as I explained before, these are element IDs that are space separated. Your list can be as long as you need it to be, but it has to have the IDs that are space separated. So this has all the same information that I had before except if you'll notice here, my itemscope is defined by this container and the table that has itemprops available to it is outside of that container. So this is an itemprop of name, affiliation, title, but it doesn't really know what it's relating to, all of that is configured up here within the itemscope itself. But since I've made the association through itemref, now when I take a look at it through the Rich Snippets Tool, I get the exact same information available. You'll notice here that the ref to item shows each one of those IDs that I created and I still am able to get access to my name, affiliation, and title. So when you're working with existing websites, itemref will quickly become a very good friend of yours.
Summary
So in working with microdata, you've seen that microdata is the ability to define data within your existing Web pages and acts as a seamless markup additive. It conforms to your current markup and doesn't make you have to shoehorn any of your existing code into some sort of specific namespace or format or anything of that nature. The value is is that you can take the exact same page that you're rendering to a user and make the exact same information available to a machine. It relies on known vocabularies and there are dozens out there. And you even have the opportunity to create your own data vocabularies if the standard ones don't specifically fit your needs. Well this is Craig Shoemaker. Thank you once again for joining me here on Pluralsight for Advanced HTML5, and I hope we meet up soon for the rest of the course here on Pluralsight.
Course author
Craig Shoemaker
Craig Shoemaker is a developer, instructor, writer, podcaster, and technical evangelist of all things awesome.
Course info
LevelAdvanced
Rating
(728)
My rating
Duration2h 45m
Released22 Aug 2011
Share course