Welcome to WebmasterWorld Guest from 18.232.99.123

Forum Moderators: open

LocalStorage. no expiration, so what do you think the user expects?

     
3:09 am on Aug 28, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 5+ Year Member Top Contributors Of The Month

joined:Mar 15, 2013
posts: 1116
votes: 110


Shout out to robzilla for turning me on to using LocalStorage!

I'm using this to auto-save every 5 seconds when a user is typing in a textarea or contenteditable. I've had a few instances where the browser crashes, a rogue ad causes a redirect, or the user just accidentally clicks on "Back" or something and loses what they've typed, so I'm trying to help prevent that.

Here's the code that I'm starting with; it uses LocalStorage if it can, or sets a cookie if the browser doesn't support LocalStorage:

// Get data if it's already been saved
// variable "saveName" is created on the parent page
var comment;
if (typeof(Storage) !== 'undefined')
comment = localStorage.getItem(saveName);

else
// getCookie is a function I wrote several years ago
comment = getCookie(saveName);

if (comment) {
// #comment is the contenteditable; if the browser doesn't support it then
// #commentText is a textarea backup
if ($('#comment').length)
$('#comment').html(comment);

else
$('#commentText').val(comment);
}

setInterval(function() {
var commentVal;

if ($('#comment').html())
commentVal = $('#comment').html();

else if ($('#commentText').val())
commentVal = $('#commentText').val();

if (commentVal) {
if (typeof(Storage) !== 'undefined')
localStorage.setItem(saveName, commentVal);

else
// setCookie is another function that I wrote a long time ago;
// the "1" sets it for 1 day
setCookie(saveName, commentVal, 1);

// #saved is on the parent page, just a DIV that says "Saved" and
// is set to style="display: none" by default
$('#saved').show()
.delay(750)
.fadeOut(1500);
}
}, 5000);


But I realize that this data never expires, so I guess the browser just sets its own limit, and when it reaches that limit then it overwrites older data?

I can see how this might be weird, though. Let's say a user is on the site and starts to send a message, then abandons the message. A year later they come back, start to send a new message... and it's auto-populated with what they wrote a year ago? That seems weird.

So I'm thinking about storing the current time with the data, and then only populating if it's less than, say, 24 hours old. So instead of just saving comment, it would be like:

var object = {comment: comment, timestamp: new Date().getTime()};
localStorage.setItem(saveName, JSON.stringify(object));


But the data would still be there, unnecessarily taking up space.

What do you guys think... would the user expect to see their abandoned post after days, months, or years? If not, is there a better way to make it auto-delete after 24 hours?

Similarly, are there any performance issues in someone's LocalStorage being large? I've read that browsers can hold up to 10MB... I would certainly never expect my users to have more than a few kb at the very most, but I need to prepare for anything, I guess.
7:43 am on Aug 28, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 5+ Year Member Top Contributors Of The Month

joined:Mar 15, 2013
posts: 1116
votes: 110


FWIW, this seems to be working to force an expiration date:

var comment, commentVal;

// Check for saved data
if (typeof(Storage) !== 'undefined') {
var getObj = JSON.parse(localStorage.getItem(saveName));

// +1 is for 1 day, you can change this to whatever you want in days
var now = new Date().getDate() + 1;

if (getObj && getObj.timestamp <= now) comment = getObj.comment;
else localStorage.removeItem(saveName);
}

else
comment = getCookie(saveName);

if (comment) {
$('#comment').html(comment);
$('#commentText').val(comment);
}

// Save data every 5 seconds; change 5000 to whatever you want
setInterval(function() {
if ($('#comment').html())
commentVal = $('#comment').html();

else if ($('#commentText').val())
commentVal = $('#commentText').val();

if (commentVal) {
if (typeof(Storage) !== 'undefined') {
var setObj = {comment: commentVal, timestamp: new Date().getDate()};
localStorage.setItem(saveName, JSON.stringify(setObj));
}

else
setCookie(saveName, commentVal, 1);

$('#saved').show()
.delay(750)
.fadeOut(1500);
}
}, 5000);


Now the only question is whether I should use an expiration date for this feature? I guess I'm leaning towards yes, unless you guys can suggest a reason not to.
2:26 pm on Aug 28, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member Top Contributors Of The Month

joined:Apr 1, 2016
posts:2627
votes: 775


I don't have an answer to your specific question but I would recommend that you consider other options to LocalStorage such as IndexedDB. It may be that for your use case LocalStorage is the right choice but be aware that there are other methods they may perform better and be more secure. Ultimately it will depend on your application.

Here are some articles to consider:
[dev.to...]

and (this is more specific to PWA's but has some useful general information:
[developers.google.com...]

More specific to your question, you can use SessionStorage which is similar to LocalStorage but the stored data is automatically deleted when the browser tab is closed, thus there will be no need for expiration.
7:05 pm on Aug 28, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 5+ Year Member Top Contributors Of The Month

joined:Mar 15, 2013
posts: 1116
votes: 110


Thanks, Nick, that's a good article to read. In this one case, though, I still think that LocalStorage is OK. From the article:

To keep it short, here's the only situation in which you should use local storage: when you need to store some publicly available information that is not at all sensitive, doesn't need to be used in a high-performance app, isn't larger than 5MB, and consists of purely string data.

That description actually fits this project perfectly.

But I'm glad you posted it, because I would be lying if I said I wasn't thinking about storing things like usernames, passwords, and other criteria there! So you squashed that idea before I wasted any time working on it :-)


More specific to your question, you can use SessionStorage which is similar to LocalStorage but the stored data is automatically deleted when the browser tab is closed, thus there will be no need for expiration.

I thought about SessionStorage, too, and it might be a better option for 99% of the people. But I, personally, have a different problem... I have 60+ tabs open all the time, and it's not uncommon that I'll start typing here, go to another tab to copy something, then when I click on the tab to come back I accidentally close the tab and lose what I was typing. Using sessions wouldn't save me in that particular scenario.

I realize that I'm probably the weirdo here, though, and that the wide majority wouldn't have that problem.

There's also a security concern with using LocalStorage with an expiration like above. Let's say that the user is on a shared computer and starts typing up a message, but then runs out of time and has to abandon what they typed. Then the next person comes along and goes to send a new message... but what the previous person typed is still there!

So maybe I should just use SessionStorage and be done with it... better yet, I should probably use SessionStorage by default, but then give the user an option to save them for longer and let them select the length of time to save them.
2:13 am on Mar 1, 2019 (gmt 0)

New User from US 

10+ Year Member

joined:May 31, 2004
posts:25
votes: 3


I love localStorage and it is great for the scenario you described. I used to use it when I built SPAs. I built some very large applications anc cached the site assets all in localStorage back in the day.
Today I use IndexedDB as the primary persistence.
You get a lot more storage, even though 5MB is a lot of storage for text, you can get several GB depending on the disk volume's capacity and available space.
IDB is also asynchronous, which means it is available to service workers.
IDB is a much more complex API, so use an abstraction library. I use localForage because it gives me an interface very similar to localStorage.

As far as your invalidation technique. I did something similar. I added an extra -ttl item so I would not mutate the actual data. I would check the TTL against the current time and if it had expired refresh from the network or just purge the expired data.

I still use localStorage to persist values that in the old days would be appended to cookies. But there is not much that should be added to cookies today thanks to browser storage options like IDB and localStorage. :)