Using HTML5 Offline Storage

Session 512 WWDC 2010

See how you can use HTML5 local data storage to improve responsiveness in your web application. Learn to create full-fledged offline web applications that can be used even when your users don't have a connection to the Internet, and discover the best practices for using these technologies in web content that's intended for Safari on iPhone OS and the desktop.

Brady Eidson: Good afternoon everyone.

Welcome to session 512, "Using HTML5 Offline Storage."

My name is Brady Eidson.

I'm an Engineer on the Safari and WebKit team.

Today we're going to be talking about data, all sorts of data, data that you as web application developers are all very familiar with.

Things like HTML, JavaScript, and CSS that make up your web applications, also the media, a lot of the images, and other UI and artworks that make our applications feel very modern and very native.

And these are types of data that you developed and then served your users from a server.

And there's something that you deliver that make up your application.

Then there's other type of data that your application creates and relies on.

Things like application state, windows sizes, window positions.

So when your user returns to the application, they might want things to look the same.

Then speaking of your users, they have preferences, all the little knobs and buttons that you give them to tweak and change the way they use their application.

You know a few other types of things about your users.

You know they're locale, they're accessibility type settings, some account info, an e-mail web app for example might have some e-mail messages an address book.

It might have some sort of social bookmarking thing and it's getting a little messy.

But it gets a lot messier when we think about the all the documents and stuff that your users create using your web applications.

And it's just getting crazy how creative a web app can be these days.

It feels a little bit like the Wild West out there because you have to wrangle all these data around without some really good supporting technologies.

You've used things like cookies which were designed for talking to a server but you've crammed a little nuggets of data into them and it's kind of worked.

And a lot of web developers have turned to plug-ins to make things work a little bit and that has its own host of problems.

And this is all keeping the data local to the browser of course.

And then there's the ultimate solution, package up the data, shipped it over the cloud, keep it on a server somewhere.

And this makes sense a lot of the time when you want to sync data to the server.

But sometimes it's just way overblown, overkill.

So we're going to give you a lasso to give you a new tool to wrangle all this data about in much better ways.

And we're going to do this using open standards developed by well-respected standard buddies.

You might have heard of this buzz word lately, HTML5.

It's a technology of standards that Apple really believes in that makes web apps do some pretty cool things.

And one of the great things about HTML5 is every major browser has announced some amount of support for it and all these offline data technologies we're about to talk about are included there.

So Safari specifically, on Mac, on Windows, and on iOS devices supports everything we're going to talk about here today.

In addition, to mobile Safari on iOS devices supporting these technologies, UIWebView native applications also support all of these things in iOS 4.

So this is Safari on all sorts of types of devices, on Macs, on PCs, and of course the new mobile hotness that runs iOS 4.

And there's something very interesting about some of these devices, the laptops, the iPads, iPod touches that they're very portable devices.

Users take them all over the place but they don't' always have a network connection.

They're not always tethered to the cloud.

So, as web application developers this kind of presents a problem and some of you might be asking yourself, "OK, well, so what can I do without the cloud?"

And that's what we're going to learn today.

Today we're going to solve three great three problems that have been plaguing us for a long time.

First, we're going to make our application itself accessible offline, packaging up all the resources that make up the application that you author and served to your users and cut the cloud out of the picture.

Then we're going to talk about a great way to persist simple data.

This is something that a lot of you have used cookies and plug-ins for a little nuggets of data and we're just going to build that right into the browser in a very reliable way.

And then for the more complex data, we're going to discuss the full on data center in the browser and we'll get to that at the end.

So first let's start at the beginning.

We have an application.

We need to make it accessible offline.

There's a fantastic new standard called the HTML5 application cache and it does that for us.

And it makes the entire application accessible offline.

All the HTML and JavaScript, CSS, all of the media that makes up the UI.

And even though cache is in the name of the spec don't conflate it with the HTTP cache.

This is a real persistent, reliable offline store of your application.

The browser will remember everything and serve things locally and it won't ever forget it until someone tells it to.

The spec also provides for automated updates of your application.

You author the content, put it up on a server, and then the browser handles getting new versions of that application to your users.

All you have to do is specify a resource manifest to make this work.

A resource manifest is just a text file with the list of URLs.

Every URL of every resource in your application has to somehow be accounted for in the manifest file.

And we'll go into a little more detail in that in a little bit.

And then there's a little new non-mandatory API.

You can completely ignore if you choose but there're some events and things you can listen to, to help you developed your application cache website and perhaps provide a richer user experience if you so choose.

So there're two fabulous advantages of using the application cache.

One, I said a couple of times, I'm going to say it again, your app works offline in a persistent reliable way but something is not quite so obvious when you're using the application cache and the browsers remembers every resource that makes up your app, is that of course your app still works online but much faster.

When the browser can completely ignore the network and just served local copies of every resource that makes up your application, things are blazing fast.

It feels a lot more native.

So how does it work?

We're using the application cache.

How is our web application loaded in the browser?

So, your user visits the URL for your web application and Safari sees that you've specified a manifest file.

It already has a copy of all the resources and the manifest.

And it just loads the local copies of the resources completely ignores the server.

So your user is already using your application and Safari now in the background without any action from you or your user change the server says, "Hey, is there any a new manifest file?

Is there a new update for this application?"

And then they'll compare any new manifest the server passes back to the manifest that has already.

And if they are different by one byte, they must be different files, each individual resource is revalidated, all the HTML, JavaScript, CSS media et cetera.

And then the next time your user visits the URL for your web application they will be using the new version of it and that's all automatic.

So to show you a demo of how we put a manifest in and make something work offline, I'm going to show you a really cool HTM5 game that a developer out there has made and it really is one of the greatest games of our time.

It's pretty cool.

I'm sure a lot of you will be very familiar with it.

And I'm a big fan T-Spin.

I'm sure you all heard of T-Spin.

Of course this is T-Spin.

This is a very professional reaching app.

It really speaks to the real T-Spin fan because it fetches that when the next televised professional T-Spin match is.

It fetches that from a server of T-Spin resources and it lets me know while I'm playing.

So this is really cool.

This is all pure native web technology.

HTML5 standards and it's the same T-Spin you all know and love.

But there's a problem with this app and I'm viewing this from a server and all the time like I take my iPad to the park for example and there's no Wi-Fi there and I just want to play some T-Spin out in nature and have the squirrels watch me play and I can't.

So the application cache is designed to solve this problem.

So let's go ahead and see if we can make this better and work offline using the application cache.

So I've already gone ahead and made a manifest file for T-Spin here.

And this is the list of all the URLs that make up the application.

The manifest file has to start with the phrase cache manifest that both the spec and the browser vendors who participate in writing the spec want to make it very strict and explicit that you are opting in to this application cache manifest because it's changing the loading model of web pages.

So one of the explicit things you have to do is start off your manifest file with cache manifest.

The other thing which I'm not going to show you, I've already done on this server, is reconfigure my web server to serve the manifest file with the text/cache-manifest mime type.

It's a specific mime type that will be in the slides later.

And those two things together tell the web browser, "Hey, this is a savvy web developer using this cool new stuff and I'm going to start showing their app offline."

So these are all the resources that are critical to make T-Spin work offline, a lot of JavaScript, a lot of images.

And then down here, we have a section called the network section.

Now, this is interesting because sometimes resources don't make sense to be cached offline.

This is the thing like the live feed that tells me when the next televised match of T-Spin is.

It only ever makes sense to be getting that from the network.

So to allow the browser to fetch that URL from the network, I need to list it in the manifest.

So I've gone ahead and done that here.

So then there's on one more change we have to do to make application cache work with T-Spin.

We have to edit our main HTML file and we have to go ahead and specify the manifest.

And now the next time the browser fetches this HTML, it's going to see there's a manifest.

It's going to fetch the manifest file and start turning on the application cache for the application.

So now we've done this.

I want to go ahead and use my iPad in the park and have the squirrels watch me play.

So I'm going to go ahead and demo this on the iPad.

Let me go ahead and load Safari here.

I'm going to ahead and visit T-Spin.

So this is a normal situation.

Wi-Fi is a little fuzzy around here.

It's having to download all of these resources like any web application normally does.

It's taking a little longer than it was earlier.

OK, here we go.

So this web this developer who made this awesome game gave us an iPad formatted control pad here so that's pretty cool.

This is still taking a lot longer than we planned but it's still progressing and in about 5 seconds I'm going to fall back and show this to you on desktop Safari, four, three, two, one, OK.

Let's just go ahead and show this to you on the desktop.

OK, so I'm going to go ahead and bring up the T-Spin app here in Safari.

So remember, I've enabled the application cache here.

So eventually, I'm going to prove to you that this does work offline.

But everything works exactly the same as it use to before and it's pretty cool.

We're loading the next match.

And actually, that's not what I was expecting to happen.

I think I see here the iPad has finished loading so I'm going to back to that.


Meanfest, that's exactly what is happening.

Thanks for calling that up.

And that's why we usually drag and drop code instead of typing it live because that type of thing happens.

OK. So I'm just going to stick with the desktop here.

So let's go ahead and refresh and see work on the desktop.

This is a little debugging aid I've patched in to those events I described that are non-mandatory.

They're optional.

And it helps me determine the application application cache is actually working.

So I'm going to go ahead and start playing it.

And it's working pretty great, except something weird happened.

It couldn't find the schedule for the next televised match.

So I bet there's probably a problem with the manifest file that caused that to happened.

So I'm going to ahead and quit Safari and take a look at my manifest.

And down here, so this was the URL for that live feed.

As I've mentioned a couple of times, every URL that our application accesses have to be accounted for in the manifest file somehow.

And this includes the URLs that come from the network that we aren't caching offline.

I probably have a typo in here.

In fact, I'm almost sure I do.

So I'm going to go ahead and do something you can only do in the network section and just replace it with an asterisk.

This is telling the application cache mechanism, "Hey, this application uses a lot of online content.

I just want to allow it to access the web at will."

So I'm going to go ahead and save my manifest file and go back to Safari and load my game, there again.

So right now, I'm viewing version 1 of the application.

The version I showed you not 20 seconds ago.

But Safari in the background has gone ahead and refetched the manifest and revalidated all the resources.

So actually, you can see that there's a missing image here because that was another part that I forgot to specify, resources, refresh.

Yeah, I think that it was.

So let's quit Safari one more time.

Watch Safari one more time, OK.

So now we're on version 3 of the application.

My script only called for two versions and there we go.

It has refetched the manifest, updated itself said, "OK, that little refresh spinning.

I can go ahead and cache that so now it's the displayable."

And now that it's allowed any fetch any URL from the network it's gone ahead and got my next televised match up there.

So now, this is locally cache in the browser and it will work offline.

So to prove that to you here on the desktop, I'm going to just to prove this to you.

This is on the different display.

I'm going to go ahead and turn off web sharing.

So the web server is now completely disabled.

I'm going to go ahead and go back to Safari and load it and it works just fined.

You can see my little red debug indicator here.

It says, "Hey, I tried to fine the manifest file but I can't because the web server isn't there anymore."

So this actually would be working on the iPad just great with the Wi-Fi disabled.

It would work out in the park with the squirrels watching me play and that would be pretty cool.

So, I can play T-Spin, one of the most exciting games of our time anywhere.

[ Applause ]

So the demo is a little rocky, but we did cover all the points I wanted to cover.

One of which I only mentioned, didn't show you.

You do have to change your server to specify, to serve the file with the correct mime type.

Then after you have text file, your list of your URLs you have to go ahead and specify that in your HTML using the manifest attribute on the HTML tag.

Now we did proved to you that resources not in the manifest due fail to load.

That little progress spinning down there in the corner and the live feed of the next televised T-Spin match so I can watch the professionals and really tune my game.

Now when I made a change in the manifest file on the server side and then refresh that in Safari that is what triggers an update of the application.

So even if you change a resource like an HTML or JavaScript file, you do have to go to the manifest file and change something to force an update.

You can use a comment to do that.

And that update process, it is automatic.

It's in the background.

Safari does it just by the mere act of the user visiting the URL.

You don't need to worry about it.

Your user doesn't need to worry about it.

It usually just works.

So that's the application cache, a way to store the entire application offline.

Now some of you web developers are murmuring, I can hear some murmurs saying, "Well, that's great now my app works offline but what about all the data it creates?

All that data we discuss earlier?"

There're a couple of solutions for that.

First, we'll talk about how to persist simple data, the little nuggets of data that many web developers are used to using cookies and plug-ins for.

And there's a great standard in HTML5 web storage standard which is designed to do just that.

Now on the web storage spec describes a standard interface for storing items of data.

And these items of data are simply key/value pairs of data.

If you're familiar with cookies which is a key string and a value string, exact same type of thing.

If you're familiar with Flash's local storage, exact same type of thing, key/value pairs of data.

It has origin-based security.

This is the standard security model in the web.

It has been for some time.

And recent HTML5 standards have really solidified it.

This means that a page served from a domain you control has access to its own set of data and only pages served from the domain you control have access to that set of data and pages from other domains do not.

So you and your apps own your data.

Now, there's various implementation of this interface.

This simple interface which I'll show you in a moment, if you already know how to program in JavaScript, you already know how to use this interface.

There're various implementations of it.

Concrete objects that have the same programming model but give you a few different abilities.

What implementations am I talking about?

The spec itself describes one called SessionStorage.

SessionStorage allows different browser tabs or windows to keep completely separate sessions from each other.

So they each have a data store that only that browser tab or window can get to.

If some of you who've tried to use cookies for session management and have noticed that your application can't be used twice and at the same time, that's the type of problem that this is intended to resolve to solve.

But the much more immediate one is the LocalStorage.

LocalStorage is a global object that all browser tabs and windows can get at and it's for persistent data.

If you set an item of data on the LocalStorage object it is saved to the user's hard drive within the browser and it will stay there persistently and reliably and it will be there, a day, a week, a month a year from now.

So those are both in the spec. If some of you started looking at developing Safari extensions, the Settings and SecureSettings objects in Safari extensions implement the exact same interface.

So it really is just a simple JavaScript programming model, the exact same interface that works for a lot of different situations.

So exactly how does it work?

I think a common thing is probably your user has a session of using your application and then they're going to quit.

So we need to save some information about their session so we can restore it later.

So we can do that with LocalStorage and SessionStorage.

Here for example, we're remembering the window location, the coordinate on the screen where the window was when the user quit.

The way we remember that is by setting the windowLocation property on the LocalStorage object.

It's that simple.

This is JavaScript programming.

You're setting a property on an object except the LocalStorage object has a very unique semantic about it which means the properties persist to disk and they're going to be there later.

So this is something that a user could quit the browser and come back a week later and fire up your web app again and the window location property will be there on the LocalStorage object.

So that works for properties, you know the name of beforehand with the dot property notation.

You can use the array, bracket property, access notation in JavaScript if you want for more variable properties.

These are just JavaScript objects that are like collections you can iterate over them.

So for example, I want to iterate over all of the data items stored in the sessionStorage because we're saving the session out.

So I can just go forth and in sessionStorage.

Then for each item, I'm just going to go ahead and move it from sessionStorage to localStorage to save it off.

And there's another API, an actual method call on these storage objects that you can use called setItem to do that.

And course, there's a removeItem for removing individual items from a storage object and you can just wipe the whole thing out at once if you chose.

So to show you a demo of how easy it is to spice up an already existing app using a little of this LocalStorage magic, I'd like to invite one of the finest T-Spin players I know, up on stage my fellow colleague, Andy Estes, up on the stage to show you how that works.

[ Applause ]

Andy Estes: So, Brady showed us this really great demo of how we can take our web application to make it available offline using the application cache and, you know, the example he use was this really fun game called T-Spin.

I've been really enjoying playing this.

A childhood favorite game of mine and, you know, now that it's implemented using these great HTML5 web technologies, I've really been having a lot of fun playing it.

And to be honest, you know, things have been getting pretty competitive in the office.

Brady and I are really always kind of jousting to see who can get top score in this game.

So, you know, one of the nice things that the developer provided for us here is tracking the score.

So you can see that as I played through here, right over here it's updating my score.

And, you know, even better, it's tracking my high score.

So, you know, Brady and I can play separate matches and we can see who gets the highest score.

Now the really nice thing about this high score is that it's persistent.

So if I were to go and, you know, quit out Safari and then decide to come back in later, I can simply go back to the game and sure enough my high score is remembered.

So this is really interesting, let's take a look at the code and see how the developer chose to implement this high score tracking.

So I'm going to leave Safari and go over to Xcode.

And I happened to have access to the JavaScript of this game of course.

So there is an object in this game called "High Score" and this object has a constructor.

So when the game starts up this constructor is called and it's initializing a property called "High Score" and it's calling its helper function called retrieveHighScore.

Now presumably, retrieveHighScore is reaching out into some sort of persistent data store, where the browser can access and seeing if a high score is there.

And if so it's pulling it in and setting this property to that value.

And if for whatever reason we get a null we'll just initialize high score to zero.

So, then as we go and play the game, we have additional properties or I'm sorry, we have some additional methods on this object that, you know, each time the score is updated, what its going to do is it's going to check to see if that score is higher than the high score and if it is it will first, you know, set the property to that new value and then also call storeHighScore.

So storeHighScore is another helper function like retrieveHighScore.

It's going to go and somehow save this value off into persistent storage.

So why don't we go and see what retrieve and storeHighScore are doing.

Let's switch over another file here.

And we see that retrieveHighScore is calling a function called readCookie, and storeHighScore is calling a function called createCookies.

So, ah-ha, we're using cookies.

And Brady covered cookies a little bit.

You know, cookies obviously work.

This game works fine with cookies but there're a couple disadvantages.

And you know, the first disadvantage is that it's really kind of the wrong idiom.

Cookies are designed to transmit data between user agents and servers but we just saw with the application cache that this application works just fine offline without any access to a server.

So, you know, a cookie isn't really appropriate in this case.

And secondly, you know, if we dig in to the implementation of these two functions, we'll see that they're actually pretty complicated.

You know, I have to build this particularly formatted string and set it equal to document.cookie.

It has to have the key/value pair.

It needs to have an expiration date and a path to send it back to the server.

You know, I care about the key/value pair, but I don't really care when it expires or what path that sent to him on the server.

But I have to provide these details, otherwise, things just wont' work.

And you know, if we look in the read cookie, things are equally complicated.

You know, I get the string back from document.cookie that has all the cookies for this domain, you know, I have to tokenize it based on a semi-colon.

I have to loop through and try to find my key.

I have to worry about if there's any white space and trim that out.

And then finally, and I'll return the substring that represents the value for that key.

So this is really complicated.

And what I'm trying to do is something really simple.

I'm trying to just persist and retrieve a simple key/value pair.

Luckily, LocalStorage provides a really simple way for us to do this effectively.

So, let's look at what these routines would like with LocalStorage.

So I'll delete this version.

And if I can find where my second screen is I'll bring over the LocalStorage version.

And, you know, wow, this is a lot simpler.

It's the same two functions, retrieveHighScore and storeHighScore.

But they're one line functions.

I went from maybe 40 lines of JavaScript down to 2 one line functions.

As Brady mentioned, you know, I'm just using the JavaScript's programming techniques that you as developers are all quite familiar with.

I have a LocalStorage object.

I'm reading a property called High Score of that object.

You can either use the dot property notation.

You can use the array access notation like I did down here.

You can use them interchangeably and either one of them will just work.

So we can say that this, you know this kind of code matches the complexity of the problem.

It's a simple problem and we can use simple code to solve it.

But it would be nice if this actually still works.

So let's say that and let's go back into T-Spin and see if I can actually still play the game.

And sure enough I can.

So my high score is reset because I'm not using my cookies anymore.

I'm using a local storage property.

But we can see it's updating as I'm playing and even better I can quit Safari, I can come back in and yeah, it maintained my high score.

So that's very cool.

[Applause] Thanks.

[Applause] Another really cool thing about using LocalStorage instead of cookies is that I can use some features of the Web Inspector to get a little more information.

So I'm going to pop-up the Web Inspector.

Across the top, I have this tab called storage.

And now that I've set a LocalStorage or yeah, a local storage property, there's now this new item in this left-hand column called Local Storage.

And if I clicked on it, sure enough I see my key/value pair that I set in code and I can inspect its current value.

And you know, even better what I can do, like I said Brady and I been really competitive, I'm really trying to beat him.

So, let's see.

[ Pause ]

Yeah, I don't think he's going to be able to beat that one but don't tell him I did that.

Well, alright, back to you Brady.

[ Applause ]

Brady Eidson: OK.

Thanks Andy.

So I stepped out for a minute I didn't see anything he might have done.

He did OK right guys?

Great. OK, so simple programming techniques, simple demo.

And that's just fantastic.

And that's the thing is it really just a straightforward if you know how to program a JavaScript.

What Andy showed is that you can use the LocalStorage object to globally and persistent store data.

You can quit the browser, relaunch, the data is still there and it will be there for the future.

And he also demonstrated, you know, no matter how you reference the property and his case, I believe those high score using the dot property, access the array bracket notation.

Or if you wanted to use the getItem call that is in the LocalStorage API.

It's all the same property and you can just choose how you want to code.

So that was web storage, simple stuff, simple data, simple straightforward solution.

But now I hear some more murmurs in the audience from some advance web developer saying "OK, I can store the simple stuff.

But I need something with a little more oomph.

I've got megabytes of data that I'm wrangling around and it's got structure and it's all this relational data" and well that's what the data center and the browser is about.

And by the data center and browser I'm talking about the HTML5 SQL databases spec. The SQL databases spec is about real-world SQL.

This is the same structured query language that many of you are familiar with form working on servers, working on infrastructure or from taking databases classes and college.

But it's the real-world SQL.

We're moving on around large amounts of data and it might take some time to process on that data.

So the API is asynchronous and it is callback-based.

Safari will handle all this stuff on a background thread and the way you interact with the database mechanism is by providing some JavaScript callback functions to take care of things when you need to.

Again, like session storage and local storage, it has the same origin base security model that is this standard security model of the web.

Pages served from your domain that you own and control but the only ones who can get at your set of databases.

So there are some advantages of keeping it local, keeping databases local.

One is of course the theme of the talk it works offline.

This is a database that is not on some server that we need to go through the cloud to get to.

This is a database accessible on our users' machines in the browser.

So this is great in some situations.

But I know a lot of you are thinking, "Well, I have this complex structure relational data that I need to store it on the serve store it on a server somewhere.

The whole point of my application or my set up is that I sync this data to a server and then I sync it back down to the browser later."

Well, you can still use the local database to cache that data locally and to prepare for the eventuality where there is no network connection.

And when you do so, you get fantastic benefits along the lines of better performance.

When the database is being created locally, fetching results from the rows and tables is just instantaneous.

And then lower latency, we're cutting the network out of the situation, we don't have to travel across the world, we don't have to travel through the airways and Wi-Fi or cellular connections, we just have to travel through our machine to the user's disc.

So things are really quick.

And then especially in this portable devices when we're disabling the radios and we're not using this power-hungry broadcast to get at this data because we have a locally cache copy of it, we can improve battery life by quite a bit.

Radios are very expensive for batteries.

So I'm going to focus on one thing back on the overview slide really quick.

And that is, real-world SQL.

What do I mean when I say real-world SQL?

I absolutely mean everything you think it means.

I mean there's tables of data that you can create and drop at will and there's rows of data you can throw massive amounts of rows at the database and it will handle them and chew them up and I'm sure there's indexes when you know the scheme of your database, you can provide performance hints to make it work faster.

There're definitely triggers you can install so you can make things work and stay consistent as data is dropped and stuff, and you bet there's transactions.

Their built into the API.

We don't let you forget them.

They're so important to performance and consistency that they're the very fundamental construct of the database API.

So how does this API work?

I'll walk you through it.

Since it's asynchronous, it takes a little bit of walking through the trails.

So let's follow the bread crumbs.

First, you get a database object to work with.

There's a new call on the window object called openDatabase.

It takes a few arguments.

The only really important one is that first argument the database identifier.

In this case, we're referring to the base called "MyDatabase."

And that's the unique identifier for the database.

If I open the same database again in the future, I'll be getting an access to the same data stored in it.

So when do that openDatabase returns you a database object?

There're a couple things you can do with it.

But by far, the most important one is start a SQLTransaction.

And the way you do that is by calling transaction on the database object.

There're a few different flavors of this method but the one that lets you actually do something useful is the one that takes a single callback function.

So starting this transaction, it's going to happen on this background thread, Safari's going to handle all the heavy lifting.

And then when the transaction is open and ready to go, that's when your callback function is going to be called.

Your callback function is going to take a single argument which is an SQLTransaction object.

And this object is where things happen, where SQL is run.

So using this object we can execute some SQL by calling executeSql.

And this is just a very simple SQL statement.

I'm creating a test table with the test value in it.

But this is where my database experience and from JavaScript in the browser begins.

So let's go into a little more depth by showing you a demo.

OK, so if any of you have researched the SQL database spec, Google around for it, one thing you might have run across is what has become the canonical example of a web database app that we put together when we first implemented.

And that is of course the WebKit Sticky Notes.

What better thing to store in a relational database than some sticky notes.

So that's what we use as our demo.

So we see here I got the sticky note I can drag around.

I can put some stuff on it.

I'm on stage mom.

So she can see that later and its storing this in the database.

Now I can go ahead and quit Safari, relaunch it, go ahead and go back to the same page and have the exact same note there as the same contents and there's actually a lot more data going on in this note behind the scenes that you might not be aware of.

First off, it's got the text of course which there we go.

But down here, it also has the last modified date.

As I move it around, it remembers the position of the sticky note.

And then of course, I might want multiple notes and you'll notice that their stacked, they have a Z order that shifts around as I select a new note.

So we also remember the Z order.

So take a quick mental snapshot here of how these notes look.

I'm going to go ahead and quit Safari, relaunch it, go back to this page and all of that information, the locations and the Z orders relations between them is stored in the database.

So it's pretty cool.

Let's go ahead and bring up the Web Inspector.

As Andy showed you earlier, it can introspect into local storage pretty well but it also has a great way to look at the databases.

So I'm guessing by looking at the Web Inspector here, we called our database Note Test because that's what shows up in the sidebar here.

And the inside of Note Test is a table called "WebKit Sticky Notes."

And indeed, these are all the notes that I have on here.

It's got the idea of the note, the text of the note, the time stamp, their locations, their Z order.

So that's all in the database here.

I can even like I have a little command prompt here so I can do some stuff in the database if I want, it has tab completion, helps out.

So the Web Inspector is a great tool to help you use database in your web application.

So right now we're looking at the sticky notes that are hosted at but I have a local copy on my laptop because I use these all the time.

I use these to organize my life because I have a lot of stuff going on and I just need a little help.

So I'm going to ahead and bring up my local copy.

Don't try to pry into my personal life too much but this is the type of stuff that's on my plate right now.

All the types of things I have to worry about.

But what is really different about my local copy is that I got it a search box up here because I have so many sticky notes flying around, it's hard to keep track of everything that's going on in my life sometimes.

So I know I need to search for things like I know I need to go shopping after the WWDC party tonight so I have a shopping list in here.

I can go ahead and type a search query, OK.

So I just "sh" was good enough so I can see my shopping list.

This is all just standard web technology here and it made everything I didn't I wasn't interested in go away and I brought up my shopping list.

And as you know it by now I'm obsessed with T-spin lately especially with beating Andy because somehow he keeps on putting up amazing scores.

So I have a lot of notes about T-spin.

I had noticed on my shopping list, I have to buy a strategy guide, I need to make sure to watch that match on TV tomorrow and so that's what I have to do regarding T-spin.

So the search box, this really changed my life.

It made using this so much easier.

So let's go ahead and see how I implemented that.

Since all these are in a database, all I had to do was write a little SQL magic and a little JavaScript to query the database for matches.

So you can see here at the beginning of my method I do a little validation to make sure I'm only performing one search at once and to make sure I reset everything to basic if there is no search query.

But then right here, the db.transaction this is where the magic starts happening.

So right here I'm calling transaction on the database object like I showed you on slides and I'm providing my callback function.

It could be a function I wrote somewhere else in my code but I went ahead and declared the function inline here, isn't JavaScript great?

So in my callback function I get a transaction object.

So I go ahead and take that transaction object and execute some SQL.

Let me make the window a little bigger here and executes some SQLs.

So this one SQL statement is leveraging the power of the database to look at all the text of all the notes and give me the matches of all the notes that I'm searching for.

So when I execute that statement, this is a different form of the function call I didn't show you in the slides.

I provide a callback to get the results out of the database because of course it's useless if we can't get the results out.

So in this callback, I'm getting a results object.

Now the documentation in the spec and in this Sticky Notes example code, you can see what the results of the object is like.

Basically, I get rows of results here.

I can just go ahead and iterate over those rows and look for the property I'm interested in, here it's the ID, and then I have those note objects live, I've already created them from the database already when I first visited the web app so I can go ahead and change some classes on them to pop the matches out and make the non-matches go away.

So you know about 20 lines of JavaScript one SQL statement leveraging the power of the database to add a really cool feature to what was already kind of a pretty cool little demo.

So that's the WebKit Sticky Notes.

[ Applause ]

So as I showed you, SQL queries available directly from JavaScript.

This is a SQL database and web technology meshed together and we can do some pretty cool stuff with it and I think you can do some pretty cool stuff with it too.

We can handle complex relational data in the browser, these sticky notes have enough little nuggets of data about them that trying to store them in local storage or cookies or in a plug-in or wrapping them up and shipping it off to a server just to fetch them again later, probably be a little bit of a pain.

So we can store that relation and that structure locally in the browser from JavaScript.

And what I didn't actually show you in the demo, but what I've alluded to and I think you can imagine is definitely true.

When it makes sense to cache this data or store it locally offline in our users' machines we get performance superior to the cloud.

Things modern machines are just so fast that handling the database for one user, piece of cake, no sweat.

And we can ignore the network, the latency and work even when there isn't a network, then that's pretty great.

So that's everything I had to talk to you about today.

We covered the application cache a standard way to store the resources that make up your application offline so your users can use your web application with no network connection at all.

We talked about the web storage spec a way to sort key/value pairs of data in a persistent and reliable manner.

And then we talked about the data center and the browser.

SQL databases a full relational database available to your JavaScript to your apps.

So for more info, you're welcome to contact Vicki Murley, the Safari Technologies Evangelist.

Each of these three technologies, are in three different specs that make up the HTML5 family of technology.

So here're the URLs for looking up at those.

We'd love to hear form you at the WebKit Open Source Project especially to check out that WebKit Sticky Notes demo.

And, of course, the Apple Developer Forums are always available for your needs.

Apple, Inc. AAPL
1 Infinite Loop Cupertino CA 95014 US