Testing localStorage/sessionStorage max data amount - javascript

I'm writing a page to test how much data localStorage and sessionStorage can save in the browser.
It works somewhat but the browser gets unresponsive and the process bar/text is not updated progressively but mostly all at onces at the end or when the unresponsive dialogbox apears.
One of the reasons for the unresponsiveness if when i create a really large string.
blablaantal might be 1048576 to create a string with 1048576 x-charachers.
data = '';
for (i = 0; i < blablaantal; i++) {
data += 'x';
}
Code and Demo : http://netkoder.dk/netkoder/eksempler/eksempel0008.html

localStorage.remainingSpace will tell you how many bytes you can store.
EDIT: In a more general case, try this:
blablaantal = 1048576;
data = new Array(blablaantal+1).join("x");

Yeah, i played around a few years ago to see if i could find a safe, performant way to test this in all browsers. I didn't. The best i achieved at the time is here:
https://github.com/nbubna/store/blob/master/src/store.measure.js
as a plugin for my store2.js wrapper. It'll work faster than your method, but it will still crash/freeze things up sometimes. Though, i haven't tried in a few years, things may be better or, i suppose, worse.

Related

JS String concatenation explodes memory consumption

I was extensively profiling a code till I found out that following code allocates more than 1GB of RAM on the latest Chrome version in private mode when the size of "array" is about 33MB, the size doesn't really matter, it's only a file that had this size with which I was running my tests.
I don't know how to generate such a big Uint8Array in the code for you test so the code below cannot be run as is, but maybe you can understand it anyways and help me with this.
const bytesToString = function (array) {
let uint8Array = new Uint8Array(array);
let length = uint8Array.byteLength;
let stringToEncode = "";
for (let i = 0; i < length; i++) {
stringToEncode += String.fromCharCode(uint8Array[i]);
}
return stringToEncode;
}
When uncommenting the "for loop", the RAM consumption stays at the same level while running my code, as soon as the "for loop" is active the consumption explodes to over 1GB. This of course gets at some point GC, but I have a general memory problem where the browser will crash eventually because of excessive memory consumption and I am trying to figure out if this function is the problem.
I could see with the performance analyzer from Chrome that GC is being called many times, I don't know how the GC from Chrome works, because you can read many "Minor GC" and at some point at the end "Major GC" and I was wondering if "Minor GC" does not really mean that the RAM is being freed but rather being "collected" and only at a later point the "Major GC" really frees RAM. If this is the case I suppose that between calling this function and "Major GC" my code runs something that also needs more RAM than usual and then the browser crashes. If this is the case it is the question if there is a better implementation for my function or can I manipulate the GC? As far as I could read, I cannot.
Strings in JS are immutable, so every time you add a character, it will create a new string that is 1 character longer than the previous one. GC will not run until everything is done, so you're stuck with tons of strings of various lengths.
You need other ways of combining strings. In this case your whole function could be written as String.fromCharCode(...array) (though if you actually want to make a string from binary data, you should consider using TextDecoder instead, which supports various encodings, caveat being that it is not available in environments such as Node.js).
Update: String.fromCharCode doesn't seem to work for very large arrays (there is a limit to number of parameters to any function), so instead you could try to map the array into 1-character strings, and then join them together:
Array.prototype.map.call(uint8Array, c => String.fromCharCode(c)).join("")
(Note the use of Array.prototype.map instead of uint8Array.map, since the latter will truncate your results to Uint8)
I think TextDecoder is probably the proper solution. But if you insist, you could also try creating a blob and then reading from it.
let blob = new Blob([arrayBuffer], {type: 'application/octet-stream'});
let reader = new FileReader();
reader.onload = function (event) {
console.log(event.target.result);
};
// Use if you want the UTF-8 encoded version
reader.readAsText(blob);
// Use if you for example need to use the result with "window.btoa" as it was in my case.
reader.readAsBinaryString(blob);

Javascript shorthand loading time

I was playing around so I ran into a JS shorthands. I know they, of course, do not change code however do they lower loading time since there is less data?
Testing codes such as one below in Chrome DOM inspector did not give me an answer (probably because they are one-line codes so it does not make any difference).
if (x == 0) {x=1} else {x=2}
x == 0 ? x = 1 : x = 2;
If your goal is to optimize the speed with which your page loads by minimizing the size of your JS payload, there are lots of tools that will automatically rebuild your files into a single bundle that is compressed (i.e., all unnecessary whitespace removed, variables/functions renamed to shorter lengths, etc.). When it comes to writing code, you should always value readability first.
Write code that other people can easily understand. Then, when you're ready to deploy, look into a tool like UglifyJS2, which will enable you to take code like this:
function square(numToSquare) {
var squareProduct = numToSquare * numToSquare;
return squareProduct;
}
square(15);
..and turn it into this:
function square(r){return r*r}square(15);
The less characters and whitespace in a file, the lower the download size of said scripts is.
Readability is also a matter of utmost importance though, and ternary operators can be confusing in certain scenarios.
I would recommend that for those cases where you expect your codebase to increase to a certain extend over time, you stick to more readable constructs and use a minification/uglification process to lower file size.

Is it a good idea to cache jQuery selections on a page level?

I am working on an intranet website where there is a lot of interaction with the main page. The site uses jQuery extensively. So I thought about caching the jQuery selections the first time they are requested and pull them from the cache for each subsequent request. (I also have built in an override if I want to force a re-selection).
Here is the basic snippet of code I am wondering about:
( function(window, $, undefined) {
var mp = {};
mp.cache = [];
mp.get = function ( selector, force) {
return ( !force || !mp.cache[ selector ] ) /*separating for readability */
? mp.cache[ selector ] = $( selector )
: mp.cache[ selector ];
}
/* more functions and code */
window.mp = mp;
window.$$ = mp.get;
})(window, jQuery);
It would be used just like a normal jQuery selection but checks to see if that selector already exists in the cache array and, if it does, just returns the results from there.
UPDATED EXAMPLE
$('#mainmenu').on('click','.menuitem', highlightSelectedMenuItem );
function highlightSelectedMenuItem () {
var menuitems = $$('.menuitem'); //selected first time, from cache every other time
menuitems.find('.current').removeClass('current');
$(this).addClass('current');
}
There are about 20 - 30 different selections in the code. So each would be cached on first call. This code will only be run on desktop clients (no phones/tablets).
Good idea? Any issues this might cause? Is there a good way to test if this helps/hurts performance? Any pros/cons you can come up with would be appreciated.
Let me know if more information is required.
Here is a fiddle to "fiddle" with.
Thanks!
Bottom line: Probably a bad idea.
You're introducing complexity that is likely unnecessary and is likely just going to eat up memory.
If you're trying to speed up selections that are repeated, then store the selection in a variable. When it's no longer needed, the garbage collector will remove it. For 99% of applications out there, that's as much caching as you need.
A big problem with your example is that the items you've selected will stick around indefinitely. Think about the people who may work on this code later. Everyone may just start using $$('....') because they see it in a few spots and it does the same thing as $('....'). Suddenly you're storing thousands of DOM elements in memory for no reason at all.
Beyond that, if the DOM changes and you don't know about it changing, the code that you have in cache is useless.. but unless you're forcing it to reload then you'll end up continuing to get that cached code. Which of course introduces bugs. In order to prevent that from happening, you'd have to force reload the cache constantly, which pretty much negates the usefulness of it.
You're going to be better off just following good, solid programming patterns that are already out there.. rather than programming up a caching mechanism that is going to be a bug magnet.
I made your question into a jsperf, and I found that un-cached jQuery appears to run faster.
http://jsperf.com/jquery-cache-array-test
because of this I would recommend just using pure jQuery.
I think it's a bad idea. If you need to use a selection in several places the save the selection to a variable.
var mySelection = $(#myId).
it will be garbage collected when its no longer needed.

Measuring JavaScript performance

I have a JavaScript file that takes an input, does some calculations with it, and returns a result. Now, I'd like to measure its performance, checking for example how much does it take to run 1.000 inputs. The problem is that I have nearly no knowledge of Javascript (the code isn't mine, neither), so I don't have any idea of how to do this. StackOverflowing I found some similar questions, but it's about "how much does it take for the script to run once" rather than "how much does it take for the script to elaborate 1.000 inputs".
If it can help, this is the script.
I would do something like this (depending on if the window console exists and has the time property):
if('console' in window && 'time' in window.console){
console.time('time');
for (var k=0;k<1000;k++) {
derp(input);
}
console.timeEnd('time');
} else {
var d = new Date();
for (var k=0;k<1000;k++) {
derp(input);
}
console.log('result: ' + new Date().getTime() - d.getTime() + 'ms');
}
if you want to measure and analyze this script, you just need to grow your javascript knowledge (at least a little bit).
then you could use a benchmarking tool like benchmark.js. you can use it in your browser or within node.js.
jsperf.com uses benchmark.js. you could set up a testcase there which should be done within minutes. it is usually designed to compare 2 scripts, but you could just put your script into both tests and you have a first indication

How to increase speed of getElementById() function on IE or give other solutions?

I have a project using Javascript parse json string and put data into div content.
In this case, all of itemname variables is the same div's id.
If variable i about 900, I run this code in Firefox 3 for <10ms, but it run on IE 7 for >9s, IE process this code slower 100 times than Firefox
I don't know what happen with IE ?
If I remove the line document.getElementById(itemname), speed of them seems the same.
The main problem arcording to me is document.getElementById() function?
Could you show me how to solve this prolem to increase this code on IE ?
Thank in advance.
var i = obj.items.length-2;
hnxmessageid = obj.items[i+1].v;
do{
itemname = obj.items[i].n;
itemvalue = obj.items[i].v;
document.getElementByid(itemname);
i--;
}while(i>=0);
Are you really noticing any latency?
gEBI is natively very very fast, I don't think you can avoid it anyway for what you're doing. Could you provide a low-down of what you're doing precisely? It looks like you're using a loop, but can you post exactly what you're doing inside of the loop, what your common goal of the script is?
document.getElementByid(itemname) is the fastest way to get a single element from the DOM in any real application you will sould not see any problems with using it, if you do see a problem you need to rethink you code a little it possible to acomplish any task with just a handfull of calls for this method. You can present you full problem if you like so I could show you an example
At least cache the reference to document:
var doc = document;
for(;;) {
doc.getElementById(..);
}

Categories

Resources