Dynamically loading Javascript and maintaining objects - javascript

I am building an ajax based website, where almost every page has it's own Javascript file which is being loaded along with html.
I have couple questions if I'm doing things in a right way, so let's get started :)
First of all, the way I execute the loaded script. All of my code is encapsulated in a function, so say I have loaded the register page, what i would do is:
page_class = "register"; //this will change when new page is loaded
new window[page_class];
So this works the way I want it to work, but I'm concerned about one thing, when the user comes back from the other page to register one more time and new object are going to be created one more time will it create memory leaks or some other bad things? If so what can I do to rerun my whole script?
My next question is fairly simple, I attach my jquery events using on and when I switch the page I loop through all elements that will be removed and detach every element, is that enough to prevent memory leaks? If not what could i improve?

So considering what we've figured out from the comments, here's my 2 cents:
I would suggest making your site sectionally ajaxed. By that I mean all music areas as one subsection, videos in another, etc. So within each section you ajax around and when transitioning to another section you gracefully fade and naturally page load the next.
.detach() in my opinion is not enough to ensure proper memory handling since detach keeps the removed section referenced. Good for when you want to recall it but useless if the user just clicked an area and backed out never to return. Now you have this reference to an entire section stored in memory.
How to handle memory in each section? You can maintain section objects. An example:
var music = {
loaded: 0,
current_track: null,
init: function(){
if(this.loaded == 0)
{
$.ajax... get your music section html and write it to the #music element
this.loaded = 1;
}
},
selectTrack: function(id)
{
// just an example
}
};
while maintaining a constant site object:
var site = {
init: function(){
// call selected page, etc
},
move: function(page){
if(page == 'music')
{
music.init();
$('#content').animate(...);
}
}
};
$(document).ready(function(){
site.init();
});
Where the site obj is initted on page load and when the move function is called it calls the init method for the respective object, which does nothing if the page has already been loaded. This example obviously depends on there being a #music element as well as a container element called #content. This part could be totally irrelevant depending on how you handle transitions. All your call, but the general idea is the same. You can always set display to none to avoid rendering bottlenecks for complex markup.
You mentioned, at least briefly, that the project was expected to pretty big. Not to be too pessimistic, but "big" is defined after the fact and not in the plan. Unless you have millions of dollars to throw at this. I'm not trying to dissuade you. By all means, make your site as you expect it to be. But consider that scaling up when demand calls is a much more sane approach than going full throttle fancy before anyone knows about it.
I only say this because I've worked for clients who have thrown millions into the gig claiming it will be the next youtube and 6 months later they were gone. Where they focused on stability and security, they failed in design and marketing. That - and pretty much that alone - is why I suggest making only sections ajaxed. It keeps it compartmentalized, the focus is easy to keep track of and you only have that one piece to worry about. When you get 10,000 users, consider going full ajax. When you get there you may also know why it might be a better move to consider ipads and tablets over a fancy ajax site. Your cool transitions and fades will be a wounded dog on mobile devices. Considering the direction things are going, is that what you want?
Again, this is only my opinion. I don't know your site or skill set or even whether or not you have already considered all I mentioned. If you have any specific questions I can try to answer or update this post.
Good luck.
Regarding the js options mentioned:
Standard jquery will likely suffice, unless you have time to fully understand something like bootstrap
Node.js is awesome but you need to make sure your server can deploy it. Dreamhost, for example, does not support it. At least they didn't last I checked. They're a good example of a decent, common host. Same for Media Temple, I think. Please correct me if I'm wrong.

Related

Is there a way to wrap an entire javascript so it only runs on a specific HTML ID?

I have inherited a third party Javascript - it's about 7000 lines when de-minified - that I need to use to open and close a panel of content when a link is clicked. It works fine when I import the HTML and js file to a content module in my CMS (DNN) but has the unfortunate side effect of breaking the bootstrap hamburger menu when the page is viewed on a mobile device.
I have neither the time nor JS skill to work out exactly how 7000 lines of script work, which bits I actually need and then adjust them so they only do what I need them to and not impact on the menu.
What I am hoping is that there is some way I can wrap the entire script so that it only applies to a specific area of the HTML and not to the menu area. I can easily assign an ID to the div that contains the code where I want it to operate.
So is there was way to do this - a way of testing at the start of the script that the current element matches the ID I assign, if it does then enable all functions in the entire script and if not then do nothing?
Update after reading initial replies...
The offending code can be seen at https://dnnplaypen.epicservices.com.au/application
The JS file (unminified version) can be found at https://dnnplaypen.epicservices.com.au/portals/0/scripts/main.unmin.js - I believe it may in fact be a complete BootStrap JS implementation which possibly explains the conflict.
and this is the relevant section of the HTML...
View them.</p>
<div id="MemberTypes" class="collapse">
<p style="margin-left:20px;"><img src="/portals/0/Images/OrangeDot.png"> <span style="font-weight:bold">Civil Intrastructure (CIM) Entrant</span></p>
<p style="margin-left:40px;">(Works in the civil industry and either supervises 1 or more people or has a civil university qualification e.g. leading hands, site supervisors, engineers, project managers, CEOs)</p>
<p style="margin-left:40px;">You’ll answer some questions about your qualification & employment details to confirm your eligibility.</p>
<p style="margin-left:20px;"><img src="/portals/0/Images/OrangeDot.png"> <span style="font-weight:bold">Student</span></p>
<p style="margin-left:40px;">(Studying civil-related course at university at least 50% of the time)</p><p style="margin-left:40px;">Please have current enrolment document(s) as evidence.</p>
<p style="margin-left:20px;"><img src="/portals/0/Images/OrangeDot.png"> <span style="font-weight:bold">Affiliate</span></p><p style="margin-left:40px;">i.e. Part of the supply chain servicing the industry</p>
</div>
Any assistance in identifying which part of the JS is invoked when the link is clicked would be much appreciated.
Possibly.
First, opening and closing an element on a click shouldn't take even 7 lines of code, let alone 7000. Refusing to look into that code is dereliction. Just throwing it into an app without knowing what it does is irresponsible.
Second, your best bet may be to use DevTools to trace the click event. In Chrome you open the Sources panel, and in Firefox you open the Debugger panel. On the right side, near the top, there is a pause icon. Click that, then click the part of the webpage that toggles the content. If you're lucky, the debugger will halt execution on the first statement in the toggle codepath, which you can and should step through.
Third, the strategy we'll use is to wrap the entire block of code inside a function that exposes a fake version of the DOM API. This 7k block of mystery code is ultimately using some of the basic DOM methods to identify and manipulate the relevant elements. Your goal will be to create a fake version of that API that only returns the specific element you care about. You'll add an ID or other identifying attribute to the element in question, and then return that element whenever the mystery code invokes your API (which it will think is the real API).
Here is a simple example:
// first, get our hands on the one element you want the mystery code to see
const elementThatShouldToggle = document.getElementById('target-element')
// second, construct an object that provides methods with the same names as what the real document provides
const fakeDOM = {
// normally, document.getElementById takes an argument
// your fake version will ignore that arg and just return the content el
getElementById: () => elementThatShouldToggle,
// you may need to mock several DOM accessor methods
querySelector: () => elementThatShouldToggle,
querySelectorAll: () => [elementThatShouldToggle]
}
// third: wrap the mystery code in a function that uses variable shadowing to obscure the real DOM, substituting your fake DOM instead
(function sandbox(document) {
/* paste the 7000 lines of mystery code here */
})(fakeDOM)
There are drawbacks to this approach:
You'll need to create fake versions of every DOM method that the mystery code uses; this will require you to run the app several times and look for exceptions. For every exception, you'll need to study the stack trace to identify any DOM methods that are implicated, and then create mocks that return safe values.
If the mystery code uses the same DOM methods as the code you like, your fake API implementations will have to be a little smarter. You may need to set up branching behavior in your fake methods that return the real elements in some cases, and safe values for all other cases. Again, this will be a guess-and-test affair.
Once the mystery code has its hands on a real DOM node, it can use the API on that node to access the entire rest of the document. It's probably not an evolving threat, so it's probably enough to then also mock the DOMNode API on the element that you provide to the mystery code.
There may be calls inside the mystery code that does scary or bad things but without using the APIs that you're studying. If you do nothing to detect or prevent that, then the bad stuff will happen, and injecting this code into your app will inject the bad stuff, too.
How will you know when you've done enough guessing and testing? Well, because you refuse to study the 7000 lines of code, there's really no way to be sure. For all we know, there's a setTimeout buried in there that does something really interesting after 45 minutes. The only way to figure that out would be to wait for 45 minutes.
With this mocking strategy, it is guaranteed that you will write far more new code than if you just wrote your own toggle script. This is hard mode. It will be complicated, tedious, brittle, and even after all of that it will not provide the guarantee that you want.
A better approach would be to use the debugger to study the codepath that gets invoked on click, and then extract that code or write a replacement. Toggling some content is generally a near-trivial task. If you need help doing that, there are countless tutorials online, no doubt including some Q&As here on SO.

Effeciency, hidden HTML or JavaScript DOM appending?

I am working on a simple Cordova app with about 4 page types and I am trying to think through which is the better way to handle the inner HTML templates.
Hidden HTML hard coded into the HTML files that is hidden and populated/revealed by my JS.
Using a JS template system and appending and removing from the DOM.
I feel that appending all that to the DOM for a page is inefficient when I could just update the sections that change. But perhaps an append is lightweight enough where I shouldn't worry about it.
There are a number of ways you can do it. In terms of load on the browser. That is hard to say. From your question it is hard to know what is in these pages, what are you displaying, is it live data, static html etc.
When you first plot out an app, if you are from the old class of building multiple page websites, it can be a little concerning as to how well your app/page will run with all those pages crammed in to one, and all that data plus code.
The answer is, amazingly well. If done properly in modern browsers, and for example Ipads the app will run to near native performance.
The options you have are
Map all the pages into one HTML document. Hide each page content using css display:none, flip them into view using css animation, fading or just display:block.
Use a javascript routing library to map urls to blocks of code that deal with each page, this makes mapping out your app much easier, and means that buttons can just link to your pages, like a real website. see http://projects.jga.me/routie/
Building all the page templates into one page can make it hard to code, as the page becomes enormous, consider breaking the inner content of each page into separate files, you can then give each page holder a url and use a small xhr request to load the page on-the fly, once loaded you can cache it into memory or even local-storage, depending on whether you remove it when it is closed or keep it hidden.
In my experience you can put an enormous number or nodes into one page and have very little speed drop, bear in mind if you use something like jquery and do a lot of $(".page > .page1 > .items li") your going to have a slow app.
Tips
Use element ID's everywhere document.getElementById(..) is 100's of times faster in a loop that $(...)
cache elements when you find them, if you need them later store them in a memory cache.
keep for loop inner code to a minimum.
use a decent click touch libary like http://hammerjs.github.io/ and delegate all the events of the body tag or at least on each page.
If you need to touch the server, load data, think dom first, device second server later. A good app is a responsive app, that responds to the user instantly.
I know this has been posted a while ago, but for the sake of the users I am going to add my answer.
I completely agree with MartinWebb but my answer will shed some light on the results of his options. I am currently working on a similar project. Please note that this answer pertains to cordova (previously called phonegap) specifically. My app has about 5 pages with +-20 different components (input's, div's, h1's, p's, etc.). This is what i tried and the result of each:
jQuery was my first option, mainly because it is easy to use and reduces the amount of code required to accomplish a said goal. Result: First time I tried this approach I though I would spice it up with animations and transformations. The result of this was a very unresponsive app. I removed the animation and transformation, however due to the nature of my application I required multiple dynamically added components and jQuery just wasn't up for the task.
Css display:none and visible:hidden was my next option. I used javascript's dom to display certain div's. Result: This works if your not planning on switching many div shortly after one another eg. a simple menu. It quickly became apparent that this wasn't going to work. Also this does not eliminate my need for the dom. Remember document.getElementById('menu').style.display = "none"; is still part of the dom. This as a solution, for me, is poor. There is a reason that var menu= document.createElement('div'); is part of the language. Which brings me to my last option.
Building a page 90% on javascript's dom was my last option. Logically I could not see how 600 lines of code cold trump one .innerHTML or .style.display = "block"; but it did. Result: It was by far the most responsive of all the solutions.
I'm not saying that all webpages should be coded with dom appending, but as I stated previously, for a cordova app of a few pages (<6), with a few components a javascript dom appending approach would be best. It takes longer to code, but you will be rewarded with control and efficiency. I would suggest coding the backbone of your app in html and populating and controlling with javascript's dom.
Best of luck.
The first option, <div>s with display:none; would be more efficient by a small margin, but you can get the best of both worlds by compiling your JavaScript and templates together into a single file using something like browserify or require.js.

Improve ASPX page performance with Telerik grids

My question is related to the improving performance of the aspx page. So after reading this Post, please comment whether it is even possible to improve the performance of this page.
Here is the scenario.
I am working on one asp.net web application with following tools
.Net 3.5
Typed Dataset(10 tables)
IE 8 Compatibility View-IE7 Standards(App does not work on FF,Chrome or any other browser)
Telerik RadControls. (Grid(s), Numeric Textboxe(s), Dropdowns with autocomplete)
App Fabric Cache.
Jquery and other page specific javascripts.
ASPX Page contains
8 Grids (out of which 6 are telerik grids and 2 are html tables)
All telerik grids have EditFormTemplates defined.
Lot of controls(I dont event know how many controls are really used, so I am not much keen into cleaning up the aspx page, as this might require lot of dev/qa efforts, which unfortunately is not an option right now.)
Lot of javascript inside the RadScriptBlock.(We also have javascrtip that fiddles around the width and other UI of the grids)
ViewState is enabled for all grids and controls on the page.
The operations on these grids are - Insert, Update, Delete, Copy, Remove all.
All these operations are done throguh parital postbacks.
There are not many database hits as most of the data is cached in appfabric.
Now this might sound weired, but there are thousands of lines of code in this single page. Approx 30k lines in code behind, 5k lines in jS and around 4k lines (html/js combined)in the aspx page.
There is complex logic in the code behind which runs on page load as well as every partial post back, and most of the grids are rebind(ed) on almost every postback.
Things we did to improve performance(which did not help much).
Note: Rewriting the entire page again was not an option so all the enhancements had to go in this page.
Minified all javascripts, CSS
Added all scripts in Radscript mangaers Script collection(I dont know if this would help in any case, but was told to do so.)
Moved all the javascript written on aspx to js files from RadScriptBlock
Refactored lot of code and minimized the use of appfabric(push,get).
RadCompression is already implemented.
All Grids use server-paging (5 records per page).
Page has hardly any static contents.
Page Caching, Fragment caching is not possible looking at the usage of this page
I dont know if this surprises anyone, but the partial postback operations on this page takes around 4-6 seconds(Request+Response+Render). I think that is pretty fas, looking at the code that is running in the background. But the client doesn't feel like that.
The expectation is that any operation on the page should not take more than 1-1.5 seconds.
Questions
Is it possible to get this performance boost looking at the infrastructure used in this page
If at all it is possible what are the things that I am missing and that could make the page perform better.
I have seen that the ItemCreated and ItemDatabound of each grid is called lot many more times than the RowCount. I know this is called for each Item i.e Header, Footer, and Items, but if I have a row count of 5 why are these methods called more than 10 times?
I have seen in the code that the developers have used Rebind() method like crazy(May be this is the reason for #3). Can any one tell me what is the correct way and location to call Rebind? I know that Telerik grids calls rebind implicity on inserts, but in what scenario do we need to call rebind explicitly?
I am trying to review the entire code base and trying to find out the bottlenecks.
I would really appreciate if anyone gives me any kind of advise which I am ready to try out on the code.
Let me know if any more information is needed.
Thank You.
EDIT
Further to the analysis, I have checked the viewstate of the entire page and it is around 33kb. Also, when I removed the AjaxSettings from the page the page loads pretty fast in 2/3 seconds. So I feel the Ajaxification of the page is creating some problem in rendering the page.
I also logged the server process timings and it takes around 1/2 seconds based on which grid is in action.
After lots of analysis, and digging through different layers, we found out there were couple of stored procedures that were the culprit. Uncessary calls were also identified to procedures, which was slowing down the page quite a bit. Fixing that gave us good performance boost. Also we had to make some tweaks in the grid rendering events.
Not sure if this answer helps someone in the future, but I hope at least it would give some pointers. Dynatrace came real handy in this excercise.
I have examples where Telerik's data access was not configured correctly which lead to hundreds of individual SQL queries to populuate a control instead of executing a single query that pulled in all the data at once.
Instead of repeating all the steps that we've taken to analyze and fix it I hope its ok if I simply post the link to the blog post I wrote about this: Link

In what order will Chrome (and others) load <img>'s? How to change this?

I have a very heavy page and I am trying to better engineer the order in which elements are loaded, preload some stuff and strategically leave other things unloaded.
Chrome seems to load the bottom of the page before the top of the page? This seems counter intuitive and I wonder if I am doing anything to cause this. Is this normal behavior? Will Chrome load elements by the order they appear in the CSS or by the order they are called in HTML?
It should have limited number of async connections for the external http calls, lets take 4 for example (they are more, something like 50) and you can have:
img_1.jpg
img_2.jpg
..
img_n.jpg
It starts to load the first 4, when one finishes, slots are getting free so it loads img_5.
On your concrete questions - leave the priority ones in the HTML and load the heavy ones by using JS I guess (you can follow the topic J L gave you above)

Serialization of the full page DOM. Can I get at the JS code that is loaded up, or must I AJAX it separately?

I have a bug I'm trying to track down, and it is very difficult to do so because of the complexity of the web app. There are many frames, and many instances of Javascript code that is embedded into the HTML in different ways.
The thing that needs to be fixed is a sub-page created with showModalDialog (so you already know it's going to be a disaster), and I am hoping that I can find a way to serialize as much of the DOM as possible within this dialog page context, so that I may open it to the same content both when the bug is present and when it is not, in hopes of detecting missing/extra/different Javascript, which would become apparent by pumping the result through a diff.
I tried jQuery(document).children().html(). This gets a little bit of the way there (it's able to serialize one of the outer <script> tags!) but does not include the contents of the iframe (most of the page content is about 3 iframe/frame levels deep).
I do have a custom script which I'm very glad I made, as it's able to walk down into the frame hierarchy recursively, so I imagine I can use .html() in conjunction with that to obtain my "serialization" which I can then do some manual checking to see if it matches up with what the web inspector tells me.
Perhaps there exists some flag I can give to html() to get it to recurse into the iframes/frames?
The real question, though, is about how to get a dump of all the JS code that is loaded in this particular page context. Because of the significant server-side component of this situation, javascript resources can be entirely dynamic and therefore should also be checked for differences. How would I go about (in JS on the client) extracting the raw contents of a <script src='path'> tag to place into the serialization? I can work around this by manually intercepting these resources but it would be nice if everything can go into one thing for use with the diff.
Is there no way to do this other than by separately re-requesting those JS resources (not from script tags) with ajax?

Categories

Resources