 Mandan Bharara works as a developer at ThoughtWorks. He's worked with Java Ruby on Rails, and he's been learning a bunch of different paradigms along the way in Java. Okay, and with the kind of applications he's been working on, he's developed a keen interest for JavaScript and has been experimenting with a bunch of client-side frameworks, Angular, Backbone, Jasmine, Phantom. He's passionate about sharing his learnings with the community, and he's co-host, oh, he's co-host events at Rails Girls. Why do I? And besides project works, he's also developed 2D JavaScript games with keyboard and mouse stuff, a prolific guy. His talk is actually about offline stuff in the browser, you know, stuff like index DB, AppCache, and local storage. You get to learn the benefits and possibilities of storage in the browser, segregation of concerns provided, how Angular plays with HTML5 offline and browser support, bunch of stuff in the next 20 minutes. Why is it playing on its own? Seems to be playing on its own. Are you hooked up? No, no, no, it is me. Oh, sorry. All right, Manan, good? Yes. All right, everybody give it up for Manan. Uh, am I audible at the back? Oh, okay, so right. Awesome. Hi, my name is Manan. Today we'll be talking about the offline capabilities of the modern browser. We'll be discussing the local storage, AppCache, index DB in a little more detail, and basically look at the segregation of concerns offered by these APIs. I'm gonna start with some facts. These are basically the internet user contributions by these various continents. If you look, Asia basically has a 48% internet user contribution. Now, without further stats, this might be easily misinterpreted. Let's scale it with the actual population of the continent. So if you look, so Asia contributes 60% of the entire world's population, of the 60%, only about 28% of the entire continent has access to internet. This situation is far worse in a continent like Africa, where the situation is around 16%. So clearly there is a need for offline. This is a very common scene in a place like a village in Africa or say India. There are no wires. There's no scope for them. So clearly they don't have internet. The only way that these people from such village dispensaries or some places can connect to internet is by going to a central facility. So how can we aid that? So I present to you this particular use case, which is clearly aided by the HTML5 APIs. So our user goes to an internet enabled facility, is able to cache whatever data he needs to be able to work offline at a later stage. He is then allowed to basically leave the internet enabled facility. Thanks to the HTML5 APIs, he can now work offline. He can do gets on the data. He can basically work on it. He can store data back on his local machine itself. And finally, whenever he gets back his internet, he can sync it to the server. Really straightforward. All right, the first API we'll be discussing is the local storage. It's a simple key value store. You only catch being both the key and the value are strings. The local storage quickly gained popularity because it was implemented by almost all of the major browsers. Another reason for its popularity was because it was the first standardized client side persistence mechanism since the traditional browser cookies that is. The API is pretty straightforward, which is why it possibly has many fans also. You're offered simple setters. The browser treats the local storage as a map, which means you can basically use the map notation to set values. The getters are straightforward as well. You can again use the map notation to fetch values. I have a simple demo that I could use. I have a local node instance running, which I can show. Now this doesn't work. That is Marlin Brando. Didn't really come out as I would have expected, but anyway, that is not relevant. We basically want to pop up in the Chrome console. Soon as I can get perfect size on this thing. Visible? Okay, okay. So in the Chrome console, as I said, the index, the local storage object is available in the window itself. So you can do window or local storage dot. You have setters. Let's say I'm gonna do, or fridge and I'll say my fridge. Now, if you look under the resources tab, you find the local storage and sorry, the local storage and you clearly see that it's the key value pair. This, I can show you quickly the getter also. It offers a similar remove item API as well. Thank you. All right, I'm gonna get back to the presentation. Okay, a fact about the local storage API is that it only offers about five megabytes of storage space in the browser, which since you can only store strings, it basically means that since each character is occupying one byte, you get to store five million characters flat. Not really. In Chrome, which uses UTF-16 encoding and uses two bytes per character, this situation is a little changed. So you only get 2.5 million characters. Now, this is really constraining. Anyway, we'll talk more about this later also, sorry. All right, the next API we'll be discussing is the application cache. The application cache is a browser cache, which basically allows you to cache content for offline use. It is for your static content, your HTML, JS, CSS, images, whatever you want to be made available offline. One thing I would not like you to confuse it with is the regular browser cache. This is not the browser cache. The primary differences lie in the fact that the regular cache headers are ignored by the application cache. This is a separate cache. It is implemented apart from the browser cache. If you use the browser cache, you would know that doing a command shift R on an Apple Mac basically does a hard refresh, forcing the content to be loaded from the server. This is not the case with the application cache. Once put inside the application cache, it will always be served from the application cache. Of course, unless it changes from the server or the user explicitly goes ahead and deletes it. You basically start working with the application cache using the manifest attribute inside your HTML tag. Then you give it a path of a file, which we call the manifest file. This is the basic format of a cache manifest. It begins with the words cache manifest. The second line here is basically a comment. You need comments because that is the only way to notify the browser that, okay, something's changed and you need to refresh the cache. The cache has three sections. The first one that we'll be talking about is cache. This is the explicit section. Whenever the page is visited, these resources will be cached for offline use. The fallback section is a little more interesting. Each entry has two values. The first one is a resource, which in case the user is offline, will be replaced by what is mentioned in the second value. It means that if the user is offline, instead of serving him the image of Einstein tongue, you'll be serving offline.jpg. The last section is the network section. You basically specify what is explicitly to be fetched from the server no matter what. Starr is a while call you say that if it is not found in the app cache, fetch it from the server. Yes, I have a demo for this as well. So let's get back the ugly sized Chrome. All right. This is a demo app that I basically prepared for showcasing AngularJS back in my office. It's a simple app. You can click on this. It then gives you this image. Then you can click on this image and it makes the text editable. One mouse out to basically bring it back. So anyway, let's make this app available offline. So I have the code. Yeah, it wasn't working. I tried. Let's see. Oh, okay. Thanks. Is the text too big? Or is it okay? This a little better? Okay. I, so as you can see, I've added this manifest attribute. So which means that it has already cached whatever content I needed. You can access this cache by going to Chrome slash slash app cache internals app cache internals, which basically shows you that for this domain, you have some entries already cached. You can view these entries. It basically tells you these are the entries that it has already cached. Which means we should now be able to run our app completely offline. All right. Let's try that as soon as I can figure out. Okay. I'm going to stop myself. So I did that. So I'm on this page. I'll do a hard refresh. So it still runs and just to showcase what we've achieved. When I click on this now, instead of presenting me with the Einstein tongue image, it is now giving me the fallback image. If you look in the network section right now, if I do a refresh on this page, you'll see that what I'm actually asking for, what the call goes for is the Einstein tongue and Albert Einstein, the different images. But because of the application cache, the response that it gets is actually the offline image. So with this, you can actually have a completely offline running application. Which works fabulously even without the network. The Einstein image I did not download. I said instead of the Einstein image, serve it with this different image when you're offline. If I bring back the server, now if I run the app, it gives me the Einstein image again. So this is, it's sort of a little smartness that is built into the application cache itself. All right. Moving on. There's some facts. It needs to be served with the manifest file needs to be served with the text slash cache manifest MIME type, the preferred extension being dot app cache. Some of the gotchas is that even if one of the resource that is being downloaded for the app cache is not downloaded, say you get a four or four or something, the entire cache is disregarded. So you need to look out for those things. Because of such things, the app cache has received many critics. It has been called as a douche bag by people. I guess at the end of the day, it basically boils down to the fact, I mean, how smart do you want your APIs to be? They could be really dumb and offer you all the flexibility in the world or they can be smart and constrain you every way possible. The next API that we'll be discussing is the index DB. This is basically a database implemented inside the browser itself. It is a simple no SQL JSON store. The benefit offered by index DB is that it allows you to create indexes on your data to fetch them later with better performance. Say you were doing the same thing with local storage, you would basically fetch the entire set and then do a find in memory. So I've been shown. So as I said, there are several benefits offered over the local storage than this. It gives you a better store in place of just storing strings, you're storing JSON data. It also understands queries, which means that you can say, okay, fetch me a particular object in which the name matches the string ABC star. So the API is actually pretty smart. The browser support, it is now supported by most of the major browsers, even Internet Explorer 10 supports it. Firefox has been supporting it ever since four or five, I think, Chrome supports it. Safari has not yet moved away from the web SQL model. So the index DB object is also found in the window. You basically initiate your work with the index DB by the open request, the first param being the name of the database, second one being the version that you're opening the database for. It basically returns to you a request object. Now this request object is the object on which several functions might be called since the entire API is asynchronous. The first method is the on-upgrade needed method. This is basically where you define your migrations. You have the handle for the database. You can define new object stores. Object stores are similar to your collections in MongoDB or tables in SQL. You can put constraints on the schema. You can set it up with some reference data that you wanna work with. Okay, the next function is the on-success. This function is called when you have the final handle of the database. In case the upgrade needed method is fired, this function is called after the upgrade needed method. You again have the access to the database, only you can't make schema modifications. You can put data, you can get data using transactions. As I've shown, I'm opening a transaction to an object store called food and the transaction is specified to be read-write. So quick demo of this thing. All right, so this is an application of just created showcase. All right, so if we check the console, it says the fridge connection successful, which means the on-success method has fired. I've just added simple console logging to whatever code I was just showcasing. So the fridge connection is successful. I can do a simple, let's say, I say put the eggs, that was not supposed to happen. I'm gonna clear the database real quick. So since I deleted the database, the on-upgrade needed event fired, which means the version upgraded console log appears. Then it says connection is now successful. You can also see under the resources tab that I now have a fridge database with the sample data that I had set up. I can now do the put the eggs in, yes, yes, it does work. Okay, so it's successful. I can look under the resources tab and hopefully now when I refresh, it gives me two objects. The second one being the eggs. So the eggs have been successfully put into the fridge. I also have a simple get. This was again shown in the code. If I do get, you can see this was fetched from the database. You have to take my word for it. Getting back, all right. So say you don't have a use case for offline. What do these APIs basically offer you? I was looking for examples. I came up with a few that I'd like to mention, just two or three. Okay, so the first one is, okay. So you present the user with a huge form. He's filling it up in the middle. He basically loses his internet connection. Now he does a submit and there is no way you can actually store it up. But what if, when he was filling the form on every blur event, you were basically saving it to the local database. There's nothing you're losing. It's on his machine itself. And when he comes back to the page after he gets back his internet, if he comes back and you can just give him an option saying, okay, you were working on something. Would you like to continue? Simple as that. Wouldn't that be cool? Your applications obviously run faster because no request is going to the server thanks to the application cache. Most of the things are fetched from your machine itself. Again, since no requests are going to the server, the server load decreases, which means your server can pay attention to more important things. So as you can see, it made six requests and no bytes were transferred. Most of it was just coming from your cache. We built this. I've been working on a project which uses these APIs heavily. So it's called OpenLMIS. It's on GitHub. If you want to check it out, it uses these APIs as well. That's my Twitter handle, it's my GitHub, and that's about it. Do I have time for any questions? You have time for two questions. Let's- A couple of questions. Any questions? Okay, all the way back there. Hey, when you're in the offline mode, when a network request is made, what is the response code? Is it still 200 or it shows something else? It's 200, but it says fetch from the cache. I think in the inspector, you can see the response is 200. Is there a way to figure out that, from where that response came from? When did I expect it from the network tab? You're saying in your code, is there a way to figure out if it came from the cache or server or? Not exactly code, but in a famine. I think from the inspector. Can I see that out there? Yes, yes, yes. For any request, the inspector basically tells you if it was served from the cache. It even tells you if the server is funded with the three or four and then it was served from the cache. So yes, you can easily figure that out. Okay. Actually, I have a couple of questions if it's okay. So the first one I saw that slide you had where a list apart calls the AppCache a douchebag. And I was just curious as to why exactly is it because you have no way to clear the AppCache? You do have a way to clear the AppCache. So then why does he? So there are a few things which are very annoying about the AppCache. The first one is that, okay, say you fetched like 15 resources, you have it running offline. Now say the content on your server changes. One of those files have changed. There is no way that you can refresh that one file. The entire application cache will have to be refreshed, which means 15 calls will go to the server. Now there are ways to handle that. There are optimizations. You can use the secondary browser cache, which will then say, okay, the rest of the files have not changed. Don't fetch those. But hey, this file is changed, fetch that. But yeah, the application cache in itself doesn't offer that smartness. That's one of the things. There are others like, one of the things is a page that uses the manifest file will use all the resources fetched from the cache. No matter what, if there's something, if there's a section called network that I showed, if you don't specify that, then it is expecting everything to be coming from the cache. If it doesn't find anything, it will break. So it's a really silly thing. I mean, so it is solved by adding a star to your network section. It's something they could have provided by default also. Okay, so the second question basically was, it's just curiosity. You said that app cache and local storage and the index DB, I think, are supported across all major browsers. Is there a standard, I mean, is it all through the same type of API? Do I have to make changes to the way I call things? No difference at all. It's just that there are some things, but they're very specific. Like internet explorers, index DB does not have composite indexes. You can live without composite indexes. You can create your own composite index on the fly. So yeah, there are workarounds, but basically the specification is constant across all of the browsers. All right, awesome. Guys, round of applause for Manu. Thank you.