There has been much discussion (example, example, example, example) recently about how the in-browser localStorage API is terrible and must be killed with fire.
My first reaction here is step away from the bacon, son, leave the bacon out of this. The localStorage API seems to have a few quoted problems, the main ones being that it’s synchronous, it does file IO, and it’s got bad event support. Put against that, rather snidely it seems, is the benefit that “it’s easy to use”.
Did I miss a meeting? Is being easy to use suddenly a bad thing? Isn’t that one of the major benefits of using Apple stuff, that it makes sense and people can get it without a PhD in computer science? Or does that only apply to users, who are presumably too busy on the sofa with a bag of Cheetos, and not to developers, who are meant to do things the hard way whenever possible?
Doing file IO and having bad event support are, certainly, issues with localStorage if you’re trying to use it for any kind of really serious data storage. If you’re Gmail, maybe you want something better. But you know what? Most of the things I build aren’t Gmail, and most of the things you build aren’t either. I don’t need event support for localStorage; I just want to stash a value in it and then move on. That’s all. Doing file IO… well, any storage mechanism had better be doing file IO at some point so that my data gets saved to disc!
Ah, no, say the detractors, but it’s synchronous. That’s bad: it blocks. This seems to boil down to two problems: it might block my tab, and it might block other people’s tabs. Now, that’s an issue, right enough. However, blocking my tab is something that I can think about and decide whether I’m prepared to run the risk or not. Because what you’re asking for is that I replace this:
localStorage.setItem("key", "value");
with this
storeSomething = function(key, value) {
var request = indexedDB.open("mydbname",
"This is a description of the database.");
request.onsuccess = function(e) {
var v = "1.0";
var db = e.target.result;
if (v!= db.version) {
var setVrequest = db.setVersion(v);
setVrequest.onsuccess = function(e) {
var store = db.createObjectStore(
"myobjectstore",
{keyPath: "timeStamp"});
var request = store.put({key: value,
"timeStamp" : new Date().getTime()});
request.onsuccess = function(e) {
// now carry on with what I was doing
};
};
}
};
}
and you know what? Given that choice… I believe I might at least sometimes choose that blocking my tab for a microsecond and very occasionally blocking my tab for two whole seconds is actually OK. I’m allowed! It’s my tab!
Fine, I’m being a bit facetious. There are problems with localStorage, and it would be good to see them resolved. But there are alternatives other than “you must ditch it and use IndexedDB, Mr Developer”, I think. What would be wrong with providing an asynchronous variant of localStorage, so I do localStorage.setItemAsync("key", "value", function() { carryon... })? Mozilla say “Implement localStorage in an asynchronous fashion in browsers – actively disregarding the spec? (this could set a dangerous precedent though)”, as if the idea of the browser manufacturers working together to adjust the spec is just impossible; did I miss something there? The spec process is open to stuff being adjusted or added to; that’s the point of it, right? And localStorage use in my tab blocking other people’s tabs… I can’t think of a nice way of saying “that’s a browser issue”, but it is. I feel sad having to say that, because I know that the engineers at Mozilla and other places have done superhuman work in this area and will continue to do so, but really one tab blocking causing others to block is surely something which is a problem for more than just localStorage?
There are problems with localStorage. Real ones. But I think that those calling for its complete removal are vastly underestimating the attractiveness of an API that’s easy to use, and also vastly underestimating how annoying it is to be forced to use something way more complicated because it copes better with pathological cases. I’d love to hear more argument on this subject, but I don’t want it to look like there’s a consensus around “it must go”. Someone needs to speak up for developers who just wanna get stuff done, like me…
I left front-end development years ago, and only recently had to go back to client-side javascript for a few minor projects; discovering localStorage was one of those rare moments when I actually felt like I was in 2012 rather than 1999.
The syntax is lovely, incredibly simple, and from a developer’s perspective It Just Works. To chuck it away, because it doesn’t conform to the grandiose visions of “SQL-in-browser” architecture astronauts, would be incredibly shortsighted. I expect browsers will stick with it, because it’s popular; everything else is an implementation detail that can be sorted out one way or the other. I’m amazed than supposedly competent people are crying that “it’s I/O on disk!” — of course it is, it’s *storage*, where the hell are you going to, you know, store bits across sessions? Even cookies are “I/O on disk” done during the request/response cycle, should we stop using cookies because “OMG my browser better not write on disk, like, ever”? “But, but… we don’t know how much space we (don’t) have!”. Implementation detail: add a couple of methods to localStorage, with some sane defaults, and off you go. “But, but… if there’s not enough space, we don’t know what to do!”… this is why try/catch was invented, my dear: just fire a bloody exception and be on your way.
I can understand the security problems — it’s a trade-off and yadda yadda, but that wouldn’t be any different with any convoluted sql-based scheme. At some point something gotta be read and written on disk, and if the browser can do it, then an attacker impersonating the browser can do it as well; there’s very little you can do there, without ending up in OS territory.
If they’re so intent on doing async APIs, it would be nice if the other browsers would implement JavaScript 1.7′s Python-style generator features.
On Firefox, it is pretty trivial to reimplement Twisted’s @defer.inlineCallbacks programming model (e.g. http://paste.ubuntu.com/853623/). With something like that, asynchronous code is almost as easy to read and write as an equivalent synchronous API.
Generators may make it into ES6. Last month’s draft has an unfinished section on generators (13.2).