store JSON data for later calls in jquery plugin - javascript

I'm writing a jQuery plugin that works on a piece of JSON data object.
This data needs to be calculated by the plugin only once, so I want to calculate it on the first call to the plugin and store it to be used in every subsequent call.
My questtion is whether there's a standard and accepted methodology for storing data used by jQuery plugins.
Assuming my plugin is:
jQuery.fn.myPlugin = function(){...}
I was thinking of storing it's calculated data in:
jQuery.myPlugin.data = {...}
Is this the acceptable way of going about it?

I think storing it there is acceptable (or jQuery.fn.myPlugin.data for that matter)...or instead use your own ID in $.cache which is for storage but uses integer IDs for jQuery events and data, so you won't have any conflict, for example:
$.cache["myPlugin"] = myData;
//and to get:
var dataToUse = $.cache["myPlugin"];
The main reason I'd take this route is it eliminates the potential jQuery.something naming conflicts that could arise with future versions.

Related

Storing temporary client side data

I need to store client side data temporarily. The data will be trashed on refresh or redirect. What is the best way to store the data?
using javascript by putting the data inside a variable
var data = {
a:"longstring",
b:"longstring",
c:"longstring",
}
or
putting the data inside html elements (as data-attribute inside div tags)
<ul>
<li data-duri="longstring"></li>
<li data-duri="longstring"></li>
<li data-duri="longstring"></li>
</ul>
The amount of data to temporarily store could get a lot because the data I need to store are image dataUri's and a user that does not refresh for the whole day could stack up maybe 500+ images with a size of 50kb-3mb. (I am unsure if that much data could crash the app because of too much memory consumption. . please correct me if I am wrong.)
What do you guys suggest is the most efficient way to keep the data?
I'd recommend storing in JavaScript and only updating the DOM when you actually want to display the image assuming all the image are not stored at the same time. Also note the browser will also store the image in its own memory when it is in the DOM.
Update: As comments have been added to the OP I believe you need to go back to customer requirements and design - caching 500 x 3MB images is unworkable - consider thumbnails etc? This answer only focuses on optimal client side caching if you really need to go that way...
Data URI efficiency
Data URIs use base64 which adds an overhead of around 33% representing binary data in ASCII.
Although base64 is required to update the DOM the overhead can be avoided by storing the data as binary strings and encoding and decoding using atob() and btoa() functions - as long as you drop references to the original data allowing it to be garbage collected.
var dataAsBase64 = "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
var dataAsBinary = atob(dataAsBase64);
console.log(dataAsBinary.length + " vs " + dataAsBase64.length);
// use it later
$('.foo').attr("src", "data:image/png;base64," + btoa(dataAsBinary));
String memory efficiency
How much RAM does each character in ECMAScript/JavaScript string consume? suggests they take 2 bytes per character - although this is still could be browser dependent.
This could be avoided by using ArrayBuffer for 1-to-1 byte storage.
var arrayBuffer = new Uint8Array(dataAsBinary.length );
for (i = 0; i < dataAsBinary.length; i++) {
arrayBuffer[i] = dataAsBinary.charCodeAt(i);
}
// allow garbage collection
dataAsBase64 = undefined;
// use it later
dataAsBase64 = btoa(String.fromCharCode.apply(null, arrayBuffer));
$('.foo').attr("src", "data:image/png;base64," + btoa(dataAsBinary));
Disclaimer: Note all this add a lot of complexity and I'd only recommend such optimisation if you actually find a performance problem.
Alternative storage
Instead of using browser memory
local storage - limited, typically 10MB, certainly won't allow - 500 x 3MB without specific browser configuration.
Filesystem API - not yet widely supported, but ideal solution - can create temp files to offload to disk.
if you really want to loose the data on a refresh, just use a javascript hash/object var storage={} and you have a key->value store. If you would like to keep the data during the duration of the user visiting the page (until he closes the browser window), you could use sessionStorage or to persist the data undefinetly (or until the user deletes it), use localStorage or webSQL
putting data into the DOM (as a data-attribute or hidden fields etc) is not a good idea as the process for javascript to go into the DOM and pull that information out is very expensive (crossing borders between the javascript- and the DOM-world (the website structure) doesn't come cheap)
Using Javascript variable is the best way to store you temp data. You may consider to storing your data inside a DOM attribute only if the data is related to a specific DOM element.
About the performance, storing your data directly in a javascript variable will probably be faster since storing data in a DOM element would also involve javascript in addition to the DOM modifications. If the data isn't related to an existing DOM element, you'll also have to create a new element to store that value and make sure it isn't visible to the user.
The OP mentions a requirement for the data to be forcibly transient i.e. (if possible) unable to be saved locally on the client - at least that is how I read it.
If this type of data privacy is a firm requirement for an application, there are multiple considerations when dealing with a browser environment, I am unsure whether the images in question are to be displayed as images to the user, or where in relation to the client the source data of the images is coming from. If the data is coming into the browser over the network, you might do well (or better than the alternative, at least) to use a socket or other raw data connection rather than HTTP requests, and consider something like a "sentinel" value in the stream of bytes, to indicate boundaries of image data.
Once you have the bytes coming in, you could, I believe, (or soon will be able to) pass the data via a generator function into a typedArray via the iterator protocol, see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array
// From an iterable
var iterable = function*(){ yield* [1,2,3]; }();
var uint8 = new Uint8Array(iterable);
// Uint8Array[1, 2, 3]
And then perhaps integrate those arrays as private members of some class you use to manage their lifecycle? see:
https://www.nczonline.net/blog/2014/01/21/private-instance-members-with-weakmaps-in-javascript/
var Person = (function() {
var privateData = {},
privateId = 0;
function Person(name) {
Object.defineProperty(this, "_id", { value: privateId++ });
privateData[this._id] = {
name: name
};
}
Person.prototype.getName = function() {
return privateData[this._id].name;
};
return Person;
}());
I think you should be able to manage the size / wait problem to some extent with the generator method of creating the byte arrays as well, perhaps check for sane lengths, time passed on this iterator, etc.
A general set of ideas more than an answer, and none of which are my own authorship, but this seems to be appropriate to the question.
Why not used #Html.Hidden ?
#Html.Hidden("hId", ViewData["name"], new { #id = "hId" })
There are various ways to do this, depending upon your requirement:
1) We can make use of constant variables, create a file Constants.js and can be used to store data as
"KEY_NAME" : "someval"
eg:
var data = {
a:"longstring",
b:"longstring",
c:"longstring",
}
CLIENT_DATA = data;
Careful: This data will be lost if you refresh the screen, as all the variables memory is just released out.
2) Make use of cookieStore, using:
document.cookie = some val;
For reference :http://www.w3schools.com/js/tryit.asp?filename=tryjs_cookie_username
Careful: Cookie store data has an expiry period also has a data storage capacity https://stackoverflow.com/a/2096803/1904479.
Use: Consistent long time storage. But wont be recommended to store huge data
3) Using Local Storage:
localStorage.setItem("key","value");
localStorage.getItem("key");
Caution: This can be used to store value as key value pairs, as strings, you will not be able to store json arrays without stringify() them.
Reference:http://www.w3schools.com/html/tryit.asp?filename=tryhtml5_webstorage_local
4) Option is to write the data into a file
Reference: Writing a json object to a text file in javascript

Vert.x Equivalent to the Node.js Global object

In Node.js you can assign values to keys off of the global object. This gives you the ability to "remember" something between requests. Assuming the node.js process doesn't die/hang and restart by a process like iisnode.
Does Vert.x have an equivalent? Essentially, I'm looking for the simplest possible cache for a piece of data so I do not have to fetch it on every request. I assume the solution on Vert.x may be able to work across threads?
the code:
{{id:1,name:"Yahoo"},{id:2,name:"Google"}}
break cause it's not valid json,you can use
{companies : [{id:1,name:"Yahoo"},{id:2,name:"Google"}]} //notice than they are inside an array
now..the doc says
To prevent issues due to mutable data, vert.x only allows simple immutable types such as number, boolean and string or Buffer to be used in shared data
that means, maybe you will need use
var map = vertx.getMap('demo.mymap');
map.put('data', JSON.stringify({companies : [{id:1,name:"Yahoo"},{id:2,name:"Google"}]}))
and then in other verticle
var map = vertx.getMap('demo.mymap');
var yourJSON = JSON.parse(map.get('data');
now..maybe a good option which would be use redis like a cache system, although the vertex map seems solve your needs so far...

dataset vs .data - Difference?

I am reading some values in data attribute fields. I have seen two easy ways to read the data as shown below:
var webappData = document.getElementById('web-app-data'),
rating = webappData.dataset.rating;
OR
var effectData = $('.effects-list li'),
creative = effectData.filter('[data-creative]').data("creative");
My question is which of these has better performance or do they really differ?
I have a page with many data attributes that I am accessing and I would like to use the method that has the best performance.
Any guidance on understanding the difference between the two would be appreciated. While I am looking at performance specifically if there are other reasons to use one over the other I would like to know this as well.
dataset is a native property of an element that contains the data attributes, it's a new(ish) addition and as such is only supported in IE11+, Chrome 8+, FF 6+ etc.
A more cross browser solution would be to get the attribute directly
webappData.getAttribute('data-rating');
data() is a jQuery method, and other than using the HTML5 data attribute to set the inital value if none exists internally, it has nothing in common with dataset.
data() stores whatever data you pass it in an internal object created by jQuery, so this for instance would fail
$(element).data('key', 'value');
element.dataset.key // undefined
as the data is not stored in the attributes at all, but internally by jQuery.
The jQuery equivalent of getting and setting the data attribute would be attr()
$(element).attr('data-key', 'value');
The native methods are probably faster, but as they are not really comparable to jQuery's data() it doesn't really matter, but for getting the data attribute I would think the fastest method with the best browser support would be
var rating = webappData.getAttribute('data-rating');

First jQuery plugin- How can I save associatedelement data in a proper fashion?

Well, this is not my first jQuery plugin but the first I think others would benefit from. So for me its the first time to make sure every possible application works as predicted.
My plugin handles modal less overlays and therefore has to save the overlay visibility in cookies.
At first I thought ok, I need one cookie to store the visibilitie. Of course this won't work as multiple elements can be overlays and therefore have different states.
The only solution I can think at this moment is, to normalize the used jQuery selector and use it as cookie path which in my opinion is no proper solution.
Additional resources
Plugin Demo
Plugin documentation and full source code
How can I save associatedelement data in a proper fashion?
Edit:
$.cookie(PLUGIN_IDENTIFIER+'IsVisible', settings._isVisible);
var isOverlayVisible = $.cookie(PLUGIN_IDENTIFIER+'IsVisible');
Store the id's with value in a JavaScript Object and then stringify / parse it with JSON:
// set;
$.cookie(PLUGIN_IDENTIFIER, JSON.stringify({ id1: true, id2: false }));
// get;
var obj = JSON.parse($.cookie(PLUGIN_IDENTIFIER));
Or use [Session|Local|Global]Storage...

What is the fastest way to get multiple data-attributes from the same element

I have a use case which requires getting multiple html5 data-attributes from elements. This occurs within a loop across many elements and pushes the data in to an array for caching.
From doing some research it appears that using el.getAttribute('data-whatever') is faster than using the native html5 dataset method however I need to get around 5 separate data attributes from the same element.
The dataset method allows you to retrieve all data-attributes with one call and then access them with standard object dot notation ( dataset.index, dataset.whatever, dataset.somethingelse ) whereas using getAttribute I have to make repeated getAttribute calls to retrieve all the needed data.
If using non compliant attributes I can of course simply use dot notation to access the properties speeding up this function considerably. But using html5 data attributes this does not work (i.e. el.data-whatever will always be undefined).
I wish to remain compliant to standards therefore I am looking for the fastest possible way of retrieving these multiple data attributes.
Thanks in advance.
I made this test:
http://jsperf.com/dataset-vs-getattribute-2
The test is a the following:
dataset all:
var data = el.dataset;
getAttribute all:
var data = {
id: el.getAttribute('data-id'),
user: el.getAttribute('data-user'),
dateOfBirth: el.getAttribute('data-date-of-birth')
};
dataset single:
var user = el.dataset.user;
getAttribute single:
var user = el.getAttribute('user');
https://developer.mozilla.org/en-US/docs/Web/API/element.dataset
Just benchmark it :
http://jsperf.com/dataset-access-vs-getattrb
It still looks to be 2 times faster using getAttribute on chrome.
I'm using a noop to prevent the JIT from optimizing it away.

Categories

Resources