Single Page App - keep pages (views) in the DOM or not? - javascript

I am building a mobile web app and thinking of the best approach to manage the app pages (say 'full screen views').
When using jQuery Mobile, the heavily used pages are all kept in the DOM. Some other framework (Backbone/Marionette) users suggest having only one page that is split into regions which update on navigation. Since my pages don't have much to share between themselves (even the header/footer changes) this means that the whole page should be rerendered on navigation if removed before.
By quickly playing around with both approaches, I have noticed that the already cached page from the DOM much quicker than rendering it all again and I didn't feel the performance issues while keeping the pages for longer time.
My question is, what is the best approach from your experiences? If the page content doesn't change much or at all, then maybe I should not remove the views. (I am talking of max 10 mid-weight pages). Cheers

I believe the conventional thing to do (and usually the most performant) is to only render enough content to fill the page. If the content cannot be seen, there is little use having it in the DOM.
However, just because that might be the conventional thing to do doesn't mean that it is the best thing for your app. If you are able to achieve noticeably better performance keeping all your content in the DOM then I do not see that as a bad approach.
You may be experiencing performance issues with the conventional approach because you do not have the experience or know-how to improve that approach yet, but you will learn those tricks eventually and that may be the best time to switch to the conventional approach over your more performant approach.

Related

angularjs and jquery performance on mobile

I'm creating a single page view website with AngularJs and jQuery intended for iPads and other tablets. I used AngularJs because it was requested by our client, but not knowing the AngularJs philosophy I decided to control click events with jQuery (big mistake, I know).
The thing is, mixing the two libraries together this way seems like it causes a lot of performance issues on mobile devices. I need to load and manipulate with animations hundreds of divs simultaneously (it's a POS app), and I was wondering if implementing directives instead of using jQuery events would give me a performance boost. If not, I really don't see the reason why I should develop directives.
Thanks in advance!
So I improved the problem thanks to a few things. First, reducing the number of angular elements greatly increases performance. Second, I used jquery-animate-enhanced for my movement animations, which also improves translations a lot! Third I used animate.css for my fade animations, which is great.
I'm still trying to improve performance with view recycling kind of like in iOS or Android, but I'm finding that ng-repeat isn't very happy with that. So, I'm probably going to have to implement directives.
Thank you!
Improve performance :
I have been through this situation and the best thing I did to improve the performance of my SPA web-app is to use native Javascript wherever possible instead of jQuery.
For example, I replaced my
$(element).html("This is some text") to element.innerHTML="This is some text"
and
$(document).on('scroll',element,callbackFuntions)
to element.addEventListener('scroll',callbackFunction,{passive:true})
Notice the {passive:true} parameter in my scroll even listener, Passing this, incredibly increased my scrolling experience and helped me get rid of the scroll-lags.
Reason to use Directive:
There might be times when you want to run a script when the particular element is created in the dom and not before it. That's when directives help a lot.

Single Page Application SEO and infinite scroll AngularJS

We are have a site with a feed similar to pinterest and are planning to refactor the jquery soup into something more structured. The two most likely candidates are AngularJS and Backbone+Marionette. The site is user-generated and is mostly consumption-oriented (typical 90/9/1 rule) with the ability for users to like, bookmark, and comment on posts. From the feed we open a lightbox to see more detail about the post with comments, related posts, similar to pinterest.
We have used backbone sporadically and are familiar with the idea but put off by the boilerplate. I assume Marionette would help a lot with that but we're open to changing the direction more radically (eg Angular) if it will help in the long term.
The requirements:
Initial page must static for SEO reasons. It's important that the framework be able to start with existing content, preferable with little fight.
we would prefer to have the data needed for the lightbox loaded already in feed so that the transition can be faster. Some of the data is already there (title, description, photos, num likes/ num bookmarks,num comments) but there is additional data that would be loaded for the detail view - comments, similar posts, who likes this, etc.
Changes to the post that happen in the feed or detail lightbox should be reflected in the other with little work (eg, if I like it from the feed, I should see that like and new like count number if I go to the lightbox - or the opposite.)
We would like to migrate our mobile site (currently in Sencha Touch) to also use the same code base for the parts that are common so we can have closer feature parity between mobile and main site.
These requirements related to my concerns about Angular:
1) Will it be possible/problematic to have initial page loads be static while rending via the templates additional pages.
2) is it problematic to have multiple data-sources for different parts of page - eg the main post part comes from embedded json data and from "see more"s in the feed while the additional detail would come from a different ajax call.
3) While the two-way binding is cool - I'm concerned it might be a negative in our case because of the number of items being rendered. The number of elements that we need two-way binding is relatively small. Posts like:
https://stackoverflow.com/a/7654856/214545
Angular JS ng-repeat consumes more browser memory
concern me for our use-case. We can easily have hundreds of posts each with 1-2 dozen details. Can the two-way binding be "disabled" where I have fields/elements that I know won't change?
Is it normal/possible to unload elements outside of the view port to same memory? This is also connected to the mobile direction because memory is even more of a concern there.
Would AngularJS work/perform well in our use-case? Are there any tricks/tips that would help here?
There are different methods of "infinite scroll" or feed as you put it. The needs of the users and size of acceptable response payload will determine which one you choose.
You sacrifice usability where you meet performance it seems here.
1. Append assets
This method is your traditional append to bottom approach where if the user reaches the bottom of the current scroll height, another API call will be made to "stack on more" content. This has it's benefits as being the most effective solution to handle cross device caveats.
Disadvantages of this solution, as you have mentioned, come from large payloads flooding memory as user carelessly scrolls through content. There is no throttle.
<div infinite-scroll='getMore()' infinite-scroll-distance='0'>
<ul>
<li ng-repeate="item in items">
{{item}}
</li>
</ul>
</div>
var page = 1;
$scope.getMore() = function(){
$scope.items.push(API.returnData(i));
page++;
}
2. Append assets with a throttle
Here, we are suggesting that the user can continue to display more results in a feed that will infinitely append, but they must be throttle or "manually" invoke the call for more data. This becomes cumbersome relative to the size of the content being returned that the user will scroll through.
If there is a lot of content being retruned per payload, the user will have to click the "get more" button less. This is of course at a tradeoff of returning a larger payload.
<div>
<ul>
<li ng-repeate="item in items">
{{item}}
</li>
</ul>
</div>
<div ng-click='getMore()'>
Get More!
</div>
var page = 1;
$scope.getMore() = function(){
$scope.items.push(API.returnData(i));
page++;
}
3. Virtual Scroll
This is the last and most interesting way to infinite scroll. The idea is that you are only storing the rendered version of a range of results in browser memory. That is, complicated DOM manipulation is only acting on the current range specified in your configuration. This however has it's own pitfalls.
The biggest is cross device compatibility .
If your handheld device has a virtual scrolling window that reaches the width of the device --- it better be less then the total height of the page because you will never be able to scroll past this "feed" with its own scroll bar. You will be "stuck" mid page because your scroll will always be acting on the virtual scroll feed rather than the actual page containing the feed.
Next is reliability. If a user drags the scroll bar manually from a low index to one that is extremely high, you are forcing the broswer to run these directives very very quickly, which in testing, has caused my browser to crash. This could be fixed by hiding the scroll bar, but of course a user could invoke the same senario by scrolling very very quickly.
Here is the demo
The source
"Initial page must static for SEO reasons. It's important that the framework be able to start with existing content, preferable with little fight."
So what you are saying is that you want the page to be prerendered server side before it serves content? This approach worked well in the early thousands but most everyone is moving away from this and going towards the single page app style. There are good reasons:
The inital seed you send to the user acts as a bootstrap to fetch API data so your servers do WAY less work.
Lazy loading assets and asynchronous web service calls makes the percieved load time much faster than the traditional "render everything on the server first then spit it back out to the user approach."
Your SEO can be preserved by using a page pre-render / caching engine to sit in front of your web server to only respond to web crawlers with your "fully rendered version". This concept is explained well here.
we would prefer to have the data needed for the lightbox loaded already in feed so that the transition can be faster. Some of the data is already there (title, description, photos, num likes/ num bookmarks,num comments) but there is additional data that would be loaded for the detail view - comments, similar posts, who likes this, etc.
If your inital payload for feed does not contain children data points for each "feed id" and need to use an additional API request to load them in your lightbox --- you are doing it right. That's totally a legit usecase. You would be arguing 50-100ms for a single API call which is unpercievable latency to your end user. If you abosultely need to send the additional payload with your feed, you arent winning much.
Changes to the post that happen in the feed or detail lightbox should be reflected in the other with little work (eg, if I like it from the feed, I should see that like and new like count number if I go to the lightbox - or the opposite.)
You are mixing technologies here --- The like button is an API call to facebook. Whether those changes propogate to other instantiations of the facebook like button on the same page is up to how facebook handles it, I'm sure a quick google would help you out.
Data specific to YOUR website however --- there are a couple different use cases:
Say I change the title in my lightbox and also want the change to propogate to the feed its currently being displayed in. If your "save edit action" POST's to the server, the success callback could trigger updating the new value with a websocket. This change would propogate to not just your screen, but everyone elses screen.
You could also be talking about two-way data binding (AngularJS is great at this). With two way data-binding, your "model" or the data you get back from your webservice can be binded to muiltiple places in your view. This way, as you edit one part of the page that is sharing the same model, the other will update in real time along side it. This happens before any HTTP request so is a completely different use case.
We would like to migrate our mobile site (currently in Sencha Touch) to also use the same code base for the parts that are common so we can have closer feature parity between mobile and main site.
You should really take a look a modern responsive CSS frameworks like Bootstrap and Foundation. The point of using responsive web design is that you only have to build the site once to accomadate all the different screen sizes.
If you are talking about feature modularity, AngularJS takes the cake. The idea is that you can export your website components into modules that can be used for another project. This can include views as well. And if you built the views with a responsive framework, guess what --- you can use it anywhere now.
1) Will it be possible/problematic to have initial page loads be static while rending via the templates additional pages.
As discussed above, its really best to move away from these kind of approaches. If you absolutely need it, templating engines dont care about wether your payload was rendered serverside or client side. Links to partial pages will be just as accesible.
2) is it problematic to have multiple data-sources for different parts of page - eg the main post part comes from embedded json data and from "see more"s in the feed while the additional detail would come from a different ajax call.
Again, this is exactly what the industry is moving into. You will be saving in "percieved" and "actual" load time using an inital static bootstrap that fetches all of your external API data --- This will also make your development cycle much faster because you are separating concerns of completely independant peices. Your API shouldnt care about your view and your view shouldnt care about your API. The idea is that both your API and your front end code can become modular / reusable when you break them into smaller peices.
3) While the two-way binding is cool - I'm concerned it might be a negative in our case because of the number of items being rendered. The number of elements that we need two-way binding is relatively small.
I'm also going to combine this question with the comment you left below:
Thanks for the answer! Can you clarify - it seems that 1) and 2) just deal with how you would implement infinite scrolling, not the performance issues that might come from such an implementation. It seems that 3 addresses the problem in a way similar to recent versions of Sencha Touch, which could be a good solution
The performance issues you will run into are totally subjective. I tried to outline the performance considerations like throttling into the discussion because throttling can drastically reduce the amount of stress your server is taking and the work your users browser has to do with each new result set appended into the DOM.
Infinite scroll, after a while, will eat up your users browser memory. That much I can tell you is inevitible but only through testing will you be able to tell how much. In my experience I could tell you that a users browser can handle a great deal of abuse but again, how big your payload is for each result set and what directives you are running on all of your results are totally subjective. There are solutions that render only on a ranged data set in option three I described, but have their limitations as well.
API data coming back shouldn't be anymore than 1-2kbs in size, and should only take about 50-200ms to return a query. If you arent meeting those speeds, mabye it's time to re-evaluate your queries or cut down on the size of the result set coming back by using child ID's to query other endpoints for specifics.
The main thing that remains unanswered in Dan's answer is the initial page load. We're still not satisfied with the approach that we have to do it client side - it still seems to us that there is a risk for SEO and initial page load. We have a fair amount of SEO traffic and looking for more - these people are coming to our site with no cache and we have a few seconds to catch them.
There are a few options to handle angular on the server side - I'll try to collect some of them here:
https://github.com/ithkuil/angular-on-server
https://github.com/ithkuil/angular-on-server/wiki/Running-AngularJS-on-the-server-with-Node.js-and-jsdom
https://github.com/angular/angular.js/issues/2104
will add more as they come up.

Best practice - pre-write HTML in document with display:none, or create with JS?

I am developing a large scale HTML5 app, and I really wonder about this issue. I will have a lot of dialog boxes and tabs that will open by user interaction.
I wonder what is the best practice - writing all the dialog boxes and tabs in the HTML document with display:none to all of them, or create these HTML sections on the fly with JS or jQuery every time the user making the relevant interaction.
What is better in terms of performance, ease of development, readability, etc?
Any help will be appreciated.
I'll try to address this question as good as I can.
1 - As I said in the comments, Avoid inline styling.
First and foremost this is because inline styling voilates DRY.
Having to repeat the same thing over and over again for this is very bad for maintenance and for developing since instead of changing code once you have to change it at ~100 places.
2 - Avoiding inline styling is also good for accessibility, some screen readers and search engine crawlers do indexing work and reading work based on css selectors and thusly using inline styling will force them to either ignore or misintrepret things.
3 - When working as developers it's easy to do inline styling "just for the fun" but what you're actually doing is mixing concerns. HTML is the content and CSS is the design.
Mixing these two usually leads to headaches and making my job as a developer that comes after you a pain in the effin ass since I have no idea what's styled and how.
Now, onto performance.
When you use inline styles, what you're telling the browser is basically "hey, for every page page view apply these styles to all of these elements." Now, this just became really apparent why this is bad.
You have no ability to cache and store your css and basically forces the browser to rerender your styles every time. Using an external CSS file will actually help you speed up your site since the browser caches it.
That was that for the css part.
The javascript you had asked about.
As I said, hide things with css and show with javascript. Now why do you want to do this instead of pulling everything in?
Well, you can do both. If you're only a webbrowser experience then you can do either, it doesn't matter. I myself prefer to have stuff in the DOM because it relates to content and if you're a large app having dozens of dozens of ajax calls will only make it harder for maintenance. I believe if you have to ajax stuff in make sure it counts and is logical and not just for the kicks (I think this applies if only you have jQuery and plain javascript at your disposal).
If you're working with backbone.js, for example, it's based on views and introduces some form of "MVC" into your frontend enabling you to have views with subviews that can pull content in from the server.
Hope that helps a bit with making a decision! :)
I would say it depends on how many tabs your application has and how big these are.
Big content inside the tabs mean that the application will take long to load when started and consume much ram. If this is the case, I suppose to load them as needed.
Small content inside the tabs will load fast, so load everything at once to increase performance when the tabs are clicked.
Don't forget to run some tests on older computers with a slow internet connection to see how your application behaves. Not everyone has the newest and fastest hardware.

Maintain height of the website

I have a client who wants to do a website with specific height for the content part.
The Question:
Is there any way that when the text is long / reach the maximum height of the content part, then a new page is created for the next text.
Within my knowledge, somehow I know this can't be done.
Thanks for helping guys!
You will probably want to look into something like jQuery paging with tabs
http://code.google.com/p/jquery-ui-tabs-paging/
Unfortunately you would need to figure out the maximum number of characters you want to allow in the content pane and anything after that would need to be put into another tab. You can hide the tab and use just a link instead.
Without more knowledge on what you're development is, this is a difficult question to answer. Are you looking to create a different page entirely, or just different sections on a page?
The former can be done using server-side code (e.g. Rails), and dynamically serving out pages (e.g. Google results are split across many page).
The latter can be done with Javascript and/or CSS. A simple example is:
<div id="the_content" style="overflow:hidden;width:200px;height:100px">
Some really long text...
</div>
This would create a "scroll" bar and just not disrupt the flow of the page. In Javascript (e.g. JQuery), you'll be able to split the content into "tabs".
Does this help?
(Almost) everything is possible, but your intuitions are right in that this can't be done easily or in a way that makes any sense.
If I were in your position, I would go up to the client and present advantages and disadvantages to breaking it up. Advantages include the fact that you'd be able to avoid long pages and that with some solutions to this problem, the page will load faster. Disadvantages include the increased effort (i.e., billable hours) it would take to accomplish this, the lack of precedent for it resulting in users being confused, and losses to SEO (you're splitting keywords amongst n pages).
This way, you're not shooting down the client's idea, and in the likely case the client retreats from his position, he will go away thinking that he's just made a smart choice by himself and everyone goes away happy.
If you're intent on splitting it up into pages, you can do it on the backend by either literally structuring your content into pages or applying some rule (e.g., cut a page off at the first whole paragraph after 1000 characters) to paginate the results. On the frontend, you could use hashtags to allow Javascript to paginate the results. You could even write an extensible library that "paginates" any text node. In fact, I wouldn't be surprised if one didn't exist already.

Too Many DOM Elements

I am building a one page webapp and it's starting to get pretty big. There are several components to the app, each one meticulously styled. On average the app has a DOM element count of 1200+. I have been warned by my YSlow scan that this is too many, and that I should have no more than 700 DOM elements.
I am usually quite strict and efficient with my markup and I doubt I would be able to trim much off. I tend to use a lot of DOM elements to get the styling exactly right and working cross browser.
How can I dramatically cut the number of DOM elements?
Will I have to load more of the content on demand (ajax) instead on all on page load?
Does a large amount of DOM elements have a big impact on performance?
I would love to hear people's experience with this and any solutions you may have...
The number of dom elements would only enter into the picture if you're doing a lot of DOM and/or CSS manipulation on the page via Javascript. Scanning for an ID in a page with 50,000 elements is always going to be slower than a page with only 500. Changing a CSS style which is inherited by most of the page will most likely lead to more redrawing/reflowing than it would on a simpler page, etc...
The only way to cut element count is to simplify the page.
We've built a single page web app. Initially Yslow worried me as we had 2,000+ DOM objects in the page.
After some work we got all the other Yslow items to green. And we ended up living with it(around 1,800 right now) as the app is very fast in various browsers.
But we don't support IE6 and IE7, and it could be different for these browsers.
How can I dramatically cut the number of DOM elements?
By using only those elements that are necessary. If you want an more elaborate advice, post your code.
Will I have to load more of the content on demand (ajax) instead on all on page load?
If you want your page to perform better on start-up, you can do that.
Does a large amount of DOM elements have a big impact on performance?
Not necessarily.
You can render elements on demand when user click a button or can use lazy loading like Twitter.

Categories