Dart: Memory management of DOM tree? - dom

I am wondering if I need to be worried about - or even be sensitive to - memory management with my Dart app.
Say I have a web app with 2 "views"/"screens"/"pages". View #1 has:
50 ButtonElements
25 LabelElements
40 InputElementss
View #2 has:
30 ButtonElements
35 LabelElements
60 InputElementss
Now let's say that there are buttons on each view to allow the user to toggle back and forth between each view, over and over again: View 1 --> View 2 --> View 1 --> View 2, etc.
I am worried about constantly recreating/reinstantiating DOM elements over and over, and eventually tying up memory resources, if the user keeps toggling back and forth between the views. So I ask:
Is this even a concern? If not, why?
If it is a concern, what programming techniques can be used to mitigate it?
Is there anything I can do to cleanup/destruct/release unused memory when I switch away from a particular view?

Memory management should always be a concern, since you will always want your app to be fast and not tie up resources it shouldn't. Garbage collection is, however, automatically performed by the browser on any object which is unreachable (not referenced in the DOM). This does not mean you should ignore this topic altogether as it is still possible to create leaks. Here's a nice tutorial on memory leaks in javascript.
In your case, it looks like the fastest option would be to keep both views in a single HTML file, then control which is shown programmatically. This way the other view is waiting in memory and ready to display. A simple way to do this would be to change the display style on the views you want to show/hide. So your views could be enclosed in divs:
<div id="view1">
//stuff in view #1 (visible)
</div>
<div id="view2" style="display:none">
//stuff in view #2 (hidden initially)
</div>
And when you want to trigger between views:
querySelector('#view1').style.display = 'none';
querySelector('#view2').style.display = 'block';
This approach will require a larger memory footprint than loading each page individually. However, it would avoid having to instantiate every element each time a view loads, and it would avoid the garbage collector running every time you close a view.

Have you looked into benchmarking your test harness ? https://www.dartlang.org/articles/benchmarking/
Seems like you can extend the benchmark base class and write your own test code to benchmark against production VM.

Related

Best practice so switch between a grid and list layout at runtime

Im currently working on a project where I want to the user to be able to chose between two layouts (list and grid) at runtime. I was searching for examples in the UI5 documentation (Sample Apps) and on GitHub, I did not find examples for how to to this or best practice examples. So I thought about how I could achieve this behaviour and had multiple ideas, but somehow none of them feels like doing this would be best practice.
Idea 1 - Destroy the "old" controls and generate the new controls inside the Controller
My first idea was to destory the controls I do not longer need. For example if the user wants to switch to the grid layout, the list and every control related it to it gets destoyed. In the controller the needed controls for the grid are created and then rendered in the view. In my eyes this would mix up view and controller logic inside the controller and does not feel like best practice
Idea 2 - Create two views and switch between them
My second idea was to create two views, each for the layout I need and switch between them. This would mean a lot of code replication in both the controller and the view. Does not feel like this would be the right way.
So I would be glad if you have own experience on this or if there is really something like a best practice for such a behaviour.
Thank you and kind regards!
I would say, idea 2 because of the following reasons:
It is best practice to work according to the MVC methodology which means separating logic, view and data. Since the controls define your view it is best to instantiate your controls in the files that are meant for it (the XML Views).
Performance: Destroying all controls means that if the user decides to switch between views, the controls have to be re-instantiated by the controller every time. This is, even though you probably won't notice it, not performant.
You don't need code replication: The argument of code replication is not necessarily true. If you can execute the same actions in the list and grid-view, it should be enough to just link the controller to both views and in that case you'll hardly have to replicate any code. Just make sure that you split your logic in enough functions. That way you might need to write some extra public functions to handle events, but not much more.

iOS 7 Safari: OS locks up for 4 seconds when clicking/focusing on a HTML input

UPDATE: The issue seems to stem from having many select elements on a page. How random is that?
So here's the issue. On iOS 7 Safari, when tapping the a text input on my site, the keyboard opens then freezes the OS for about 2-5 seconds then finally scrolls to the input. After this happens once, it never happens again until you refresh the page. I've looked all over the place, and yes, iOS 7 Safari is super buggy, but lets try and see if we can figure this out.
Note: This does not happen in any other mobile browser or any previous iOS Safari. It happens both on the ios 7 iphone and ios 7 ipad.
I will list everything my friend and I have tried so far:
Removed the ability to add event handlers in jQuery. (Note: all our event handlers are assigned through jQuery except for unload and onpageshow).
Removed the jQuery autocomplete script from the inputs.
Removed all JavaScript from the inputs.
Removed all third-party libraries being added on the page by rejecting the domains on the Mac.
Switched back to previous jQuery versions. The last one we could actually use before nothing worked was 1.7.0.
Switched back to previous jQuery UI versions.
Changed input event handling to delegate and live, instead of on('click')
Removed all CSS classes.
Removed all CSS from the page. Note: The response time for the OS this went down to 1-2 seconds but still happened.
Does anyone have any ideas?
Thanks a bunch!
(There are some somewhat-effective solutions, see near the end of the list)
At my company we are also suffering from this. We filed an issue with Apple but have heard mum.
Here are some interesting jsfiddles to help illustrate some of the issues, it definitely seems to revolve around the number of hidden fields, and textareas do not seem to be affected.
From debugging efforts, my guess is that there is some functionality trying to detect if an input is a credit card or phone number or some special kind which seems to cause the locking behavior. This is just one hypothesis though..
Summary:
On a page with a form containing named input elements inside containers that are marked "display: none", the first press on an input in that form has a very noticeable delay (20sec-2min) between the keyboard coming up and the input being focused. This prevents users from using our web app due to the enormous time spent with the ui frozen waiting for the keyboard to respond. We have debugged it in various scenarios to try and discern what is going on, and it appears to be from a change in how iOS7 parses the DOM versus how it did on iOS6, which has none of these issues.
From debugging within Safari's Inspector with the iPad connected, we found that iOS7 provides much more information about the (program)'s activities, to the point that we found that _CollectFormMetaData is the parent of the problem. Searching for meta data causes massive churn that increases more than linearly along with the number of hidden containers containing inputs. We found that _isVisible and _isRenderedFormElement are called far more than they reasonably should be. Additionally, if it helps, we found some detection functions relating to credit cards and address books were large time consumers.
Here are some jsFiddles for illustration. Please view them in Safari on an iPad running iOS6 and then on an iPad running iOS7:
http://jsfiddle.net/gUDvL/20/ - Runs fine on both
http://jsfiddle.net/gUDvL/21/ - Just noticeable delay on iOS 7
http://jsfiddle.net/gUDvL/22/ - More noticeable delay on iOS 7
http://jsfiddle.net/gUDvL/29/ - VERY noticeable delay on iOS 7
http://jsfiddle.net/gUDvL/30/ - Same as 29 but with none hidden - no delay on iOS 7
http://jsfiddle.net/gUDvL/38/ - Same as 29 but further exacerbated
http://jsfiddle.net/gUDvL/39/ - 99 hidden inputs, one visible, one separately visible
http://jsfiddle.net/gUDvL/40/ - 99 hidden textareas, one visible, one separately visible
http://jsfiddle.net/gUDvL/41/ - 99 hidden inputs, one visible, one separately visible, all
with the autocomplete="off" attribute
http://jsfiddle.net/gUDvL/42/ - 99 hidden inputs, one visible, one separately visible. Hidden by position absolute and left instead of display.
http://jsfiddle.net/gUDvL/63/ - Same as gUDvL/43/ but with autocomplete, autocorrect, autocapitalize, and spellcheck off
http://jsfiddle.net/gUDvL/65/ - Same as gUDvL/63/ but with cleaned up indentation (seems slower on iPad)
http://jsfiddle.net/gUDvL/66/ - Same as gUDvL/65/ but with display none via css again instead of DOMReady jQuery
http://jsfiddle.net/gUDvL/67/ - Same as gUDvL/66/ but with TedGrav's focus/blur technique
http://jsfiddle.net/gUDvL/68/ - Same as gUDvL/66/ but with css driven text-indent instead of display:block again (noticeable improvement - reduction to 2-3 secs for initial focus)
http://jsfiddle.net/gUDvL/69/ - Same as gUDvL/68/ but with TedGrav's focus/blur re-added
http://jsfiddle.net/gUDvL/71/ - Same as gUDvL/66/ but with js adding a legend tag before each input. (noticeable improvement - reduction to 2-3 secs for initial focus)
<input type="text" autocomplete="off" /> (links to jsfiddle.net must be accompanied by code..)
(We should note that having the iPad connected to a Mac with Safari's debugger engaged dramatically emphasizes the delays.)
Steps to Reproduce:
Load any of the above jsfiddles on the iPad
Press an input to gain focus
Watch screen until you can type
Expected Results:
Expect to be able to type as soon as the keyboard pops up
Actual Results:
Watch the keyboard pop up and the screen freeze, unable to scroll or interact with Safari for a duration. After the duration, focus is given as expected. From then on no further freezes are experienced when focusing on inputs.
tl;dr technique summary
So overall there are a couple proposed fixes from various answers:
Don't hide the divs with display: none - use something like text-indent
Short circuit Apple's metadata scanning logic - many form tags or legend tags seem to do the trick
Auto focus/blur - Did not work for me but two people reported it did
Related threads at Apple:
https://discussions.apple.com/thread/5468360
There seems to be a problem with how IOS handles the touch-event for inputs and textareas. The delay gets larger when the DOM gets larger. There is however not a problem with the focus event!
To work around this problem you can override the touchend event and set focus to the input/textarea.
document.addEventListener("touchend", function (e) {
if (e.target.nodeName.toString().toUpperCase() == 'INPUT' || e.target.nodeName.toString().toUpperCase() == 'TEXTAREA') {
e.preventDefault();
e.target.focus();
}
});
This will however create a new problem. It will let you scroll the page while touching the input/textarea, but when you let go, the site will scroll back to the original position.
To fix this, you just need to check if any scrolling has occured, and surround the preventDefault and target.focus with an if statement.
To set the original position, you can use the touchstart event.
document.addEventListener("touchstart", function (e) {
... //store the scrollTop or offsetHeight position and compare it in touchend event.
}
EDIT Me and a colleague have improved it a little bit, and it works like a charm.
var scroll = 0;
document.addEventListener("touchstart", function (e) {
scroll = document.body.scrollTop;
});
document.addEventListener("touchend", function (e) {
if (scroll == document.body.scrollTop) {
var node = e.target.nodeName.toString().toUpperCase();
if (node == 'INPUT' || node == 'TEXTAREA' || node == 'SELECT') {
e.preventDefault();
e.target.focus();
if(node != 'SELECT') {
var textLength = e.target.value.length;
e.target.setSelectionRange(textLength, textLength);
}
}
}
});
Struggled with this issue as well within an ios fullscreen which was inserting /removing pages containing a single input element. Was experiencing delays up to 30 seconds with only a single visible text input element on the page (and within the entire DOM). Other dynamically inserted pages with single or multiple text inputs in the same webapp were not experiencing the input delay. Like others have mentioned, after the initial delay, the input field would behave normally on subsequent focus events (even if the dynamic page containing the input element was removed from the DOM, then dynamically re-rendered/inserted back into the DOM).
On a hunch based on the above behaviour, tried the following on page load:
$("#problem-input").focus();
$("#problem-input").blur();
While the above executes immediately with no delay, the end result is no subsequent delays when the input gets focus via user interaction. Can't explain the reason behind this working, but it appears to work consistently for my app while other suggested fixes have failed.
I have the same freezeing problem.
I am not sure we're in the same situation.
here is my demo:http://tedzhou.github.io/demo/ios7sucks.html
In my page, i use a <p> element with onclick attribute as a button.
When user click on the button, page change to a textarea.
Then a click on it will freezes the browser.
The time freezing spent relevent to the numbers of the dom elements.
In my pages, there are 10000 elements, which make it freeze by 10+ seconds.
We can solve the problem by switching the <p> element to the real <button>, or reducing the nums of dom elements.
ps: sorry for my poor english. LOL
The main issue for me was with hidden fields. Made the form hang for 10-15 seconds.
I managed to get around by positioning the hidden form fields off the screen.
To hide:
position: absolute;
left: -9999px;
To show:
position: relative;
left: 0;
Met the same problem in quite complex application having many inputs.
Attached debugger to Safari iOS7 via USB and logged UI events. I see "touchend" event coming as soon as I am clicking on textarea (or any input) and in 10-20 seconds after that I see "click" being dispatched.
Clearly it is a bug in Safary as on other devices like Android or iOS6 there is no problem with the very same application.
It happens not only in iOS but in safari 7 for MAC OS (Maverics) too, I have found that the problem happens when you use a lot of div tags to contain inputs (or selects) within a form:
<div> <select>...</select> </div>
<div> <select>...</select> </div>
...
I changed the layout of my selects to use ul/li and fieldsets instead of divs and the freezze time was reduced drastically.
<ul>
<li><select>...</select></div>
<li><select>...</select></div>
</ul>
Here are two examples in jsfiddle:
freezze for 5 seconds
http://jsfiddle.net/k3j5v/5/
freeze for 1 second
http://jsfiddle.net/k3j5v/6/
I hope it might help someone
For me, this issue was being caused by user inputs being hidden on the page with display:none.
The workaround I used: instead of hiding inputs with display:none, I used jQuery's detach() method on document ready to 'hide' all the user inputs that were not being used. Then append() the inputs when they were needed.
That way no inputs had display:none on when the page was first loaded and so no delay occurred on the initial user interaction.
We had the same or a similar problem at my company. Whenever we displayed a large number of drop down lists and then a user clicked on a drop down, IOS 7 would freeze the page for a minute or two. After it unfroze, everything would work properly from that point forward.
This affected all input types. The large number of drop downs were actually hidden on first load - the user would initiate the display of the drop downs. Until the drop downs were displayed - everything would work fine. As soon as they were displayed, the next input click, even an input that had been working properly, now would cause the browser to freeze.
As others have noted, it seems that IOS 7 has a problem when parsing the visible inputs in the DOM after the user first interacts with an input. When the number and/or complexity of the elements/options/DOM are higher, the freeze is more pronounced.
Because it always froze on the initial user interaction, we decided to initiate a hidden user action as soon as we displayed the list of drop downs. We created a transparent button (it could not be hidden - it had to be "displayed") and initiated a click on it as soon as the user opened the drop down list. We thought that this would make IOS start parsing the DOM quicker, but found that it actually fixed the problem completely.
I have encountered this problem as well since I noticed many people are still having a problem with this I thought I'd put my solution.
Basically my solution is server side hiding of elements.
My page is ASP.NET so I wrapped my divs with the inputs with Panels and set these panels as Visible false.
This way if I click on an input the safari can't see all the other controls since they are hidden server side.
Of course if you want to make this work a little like clientside jquery you'll need automatic postback and an updatepanel somewhere.
This solution requires an effort but still its better than actually trying to fix a safari bug.
Hope this helps.
My answer might be slightly off the main topic, but I did arrive here after some searching as the scenario "feels" similar.
Issue:
My issue felt like a lockup in iOS, but not quite, since other elements on the page were still interactive. I had an <input type="search" /> element, that would not focus when I clicked into the field. But it would eventually catch focus after about 4-5 taps on the screen.
Additional Info:
My project is a hybrid app: WebView inside of an iOS app. The site is built with Twitter Bootstrap.
Solution:
I happened to also have the autofocus attribute set on the element. I tried removing that and it worked... no more consecutive taps to get the field to focus.
iOS 12.1.1 - December 2018
Here is a simple fix that worked in my case:
window.scrollTo(0,0) // attached to 'blur' event for the input fields
While it may not be ideal in terms of UX (especially if you have a form with many fields), it's definitely better than having 10+ second freezing time.
have you tried to turn off "Password & Autofill" > "Credit Cards" into Safari settings ?
After this operation it works fine. This isn't a final solution but maybe the problem's reason on iOS.

Backbone Model View: Switch between editing (via form) and display

With Backbone I have created a view for a model. I would like to provide the following workflow to the users:
a) Initially, model content is just displayed via a template and there is an edit button
b) if the user clicks the edit button, the model content will be displayed in a form and can be saved back to the model by clicking a save button.
c1) if saved successfully, the new model content we be rerendered via the template and displayed again
c2) if there were any validation errors, the form is updated with the errors.
I came up with the following options on how to implement this. But I am not sure, on the best practices. Any advice is highly welcome.
Option 1: 2 sub views (one for the displaying the content, one for editing it) that are dynamically created on any switch between display and edit (and dropped afterwards).
Option 2: 2 sub views (one for the displaying the content, one for editing it) that are hidden/unhidden on any switch (like toggle)
Option 3: 2 sub views (one for the displaying the content, one for editing it) that are assigned to the parent element on any switch.
Option 4: 1 View to manage the model content and 2 templates (one for displaying and one for editing) that are rendered on any switch between between display and edit.
From my gut feeling, I clearly would prefer option 4, since it will need ony 1 view that could handle all logic. But maybe I have overseen something in terms of performance, event handling, DOM access etc. So any hard arguments on the pros and cons of the 4 options are highly appreciated.
What do you think?
I've been working on something like this except that the edit button is attached not to the whole model, but to individual attributes, which can be edited "in place". To do that I've been using backbone-forms, replacing the element to be edited by a backbone form and then re-rendering it after the form has been submitted. This works quite well.
In your case, since you're editing the whole model at once, it would actually be easier. When the user clicks the edit button, replace the view with a backbone form, and when they submit that re-render the model view with the errors or success message. Backbone forms makes displaying error messages on the form quite easy.
I have tried option 3 (2 subviews) and option 4 (1 view using 2 templates).
Here is an argument for 3:
Switching between readonly view and edit view in backbone js
And here is an article promoting 4, under "Switching a Contact Into Edit Mode":
http://net.tutsplus.com/tutorials/javascript-ajax/build-a-contacts-manager-using-backbone-js-part-4/
I found option 3 to more trouble, because now you have 3 views using the same model. It brings up issues in the DOM, because now there is an el for the parent and an el for each child, nested inside. It also brings up issues with encapsulation, because the child views should really be inherited from the parent, but that's difficult with javascript:
Access parent class member with javascript inheritance?
I wanted option 3 to work more like an abstract base class tied to the el in the DOM. Then view and edit could inherit from it and internally set the el, preventing nesting of two els. But this breaks how backbone.js nests views:
Swap/switch/exchange backbone.js views in place?
Option 4 "just worked" the first time I tried it. It's trivial to have an editTemplate that gets rendered if View.editing is true. And in practice, the read-only view tends to be so small, with so little interaction by definition, that it only adds to an edit view by a few lines.
The downside to 4 is that you dirty your view with switching logic.
An argument for 4 is that it increases the possibility to reuse code and reinforce DRY.
One last argument for 4 is that you might have a "rich" form at some point that is always on, and maybe you only want to enable editing on specific form elements. For example a Contact form might have an Address view inside that handles its own updating. So view/edit might not be mutually exclusive down the road.
I finally resigned myself to going with what worked (option 4) because both options use two templates in the html file. The backbone.js implementation details don't matter to the end user.
I think this is all worthy of some lengthy articles weighing the pros and cons of each approach, with real-world examples. Backbone.js also needs to have backbone-relational built into it, and probably Backbone.ModelBinder, with a better ._super implementation. If some of these concepts were more fleshed out, it would make it easier to implement option 3 IMHO.
But I'm curious what others think, because neither 3 or 4 are perfect as they stand now, and I'd like to know what the best practices are for this, since form handling is one of the primary reasons that people get into backbone.js in the first place.

How to wait for DOM operation completion?

I have to maintain a part of an old Windows VB6 project (so, don't tell me to migrate-it to VB.NET). This program embeds the well known webbrowser control (IE) in which it loads local HTML files (containing different stats, but doesn't matter). Knowing we don't want any scroll bar in the web browser view (even if HTML page is longer than the webbrowser window, we just need to see what it's on top), we manage DOM on DocumentComplete event like this :
Private Sub wb_DocumentComplete(ByVal pDisp As Object, URL As Variant)
wb.Document.documentElement.Style.overflow = "hidden"
ProcessWithDStats
End Sub
All sounds right and the vertical scrollbar well disappear, but now, I need to add some stuff in the ProcessWithDStats sub (a big sub calling a lot of functions) which need to be sure the previous DOM operation is totally completed (I mean : scrollbar hidden and it's content re-justified accordingly to this new width w/o scrollbar).
So, how to do ?
At this time, ProcessWithDStats is executed before DOM management really finish to be rendered !
Until now, here are my attempts :
I've tried to add a scrollbar testing (comparing doc width and browser client area one) between the two lines, but it doesn't work : test is OK, but reflow of text (because of this change of width when scrollbar disappear) has not enough time for being applied before ProcessWithDStats is engaged.
I've tried to Sleep(), but it locks entire program (webbrowser rendering included)
Well is there a way to wait for real application of the given DOM management in this WebBrowser control ?
I mean something like :
Do
Doevents
Loop Until [DOM modification and rendering completed]
you need to do this... at the very least.
Do
Sleep 100
Doevents
Loop Until wb.Busy = False And wb.ReadyState = 4
On your version the .Busy may be called .IsBusy but are the same thing.
Also, there are additional things you should do if you want to truely know if a browser is done loading, read some of my previous answers if you want to know more, or need more accuracy than the above, but what i have included for you is for sure a much better solution than you currently have. Let me know if you need it to work on 100% of websites or just a select few, if a select few than this simple method may be enough.
Let me know hwo it goes anyway, cheers.

Which template should i choose for iphone app having multiple pages to view without more memory consumption

I want to develop an app having multiple pages. For example the first page has all menus in it. If you click on one menu it will go to some list page. If you click on some items in the list again it goes to another page with full details of that item and it goes on. In every page there is another menus relevant to that page. If i click on that menu it will take me to that particular page and come back to same page from where i clicked the menu.
I searched through the web and i came across that Navigation-Based template is best to implement this.
I had little concern in memory management point if i navigate from one page to another continuously for more than 3 or 4 pages Navigation-Based approach will keep all the views in the stack which eats lots of memory. Is this a best approach or is there any workaround to implement this kind page navigation.
Whether the Navigation-Based approach will take care of memory problems when i navigate from one page to another. If my understanding is wrong correct me.
Seems that you take the memory management part too high.
Why shouldn't you use a predefined function which is used in million other apps?
Or another question which really (and I mean really) big interface which will consume 40 mb of memory? The iPhone is really efficient with it's own UI. Your first part in memory management is to take care of your allocations so that no leaks appear.
The views stay in memory and should stay in memory because no one want to wait a few seconds while navigating from one view to another. (But of course you can remove unnecessary UI elements while of screen)
Do use UINavigationController, it's the best one for your needs.
And also read something about viewDidLoad / viewDidUnload methods of UIViewController class. These are called when your view is not "visible" (= unloaded) and loaded again. They help you to use memory efficiently. You should also look at memory warnings (didReceiveMemoryWarning method).
It's quite simple - in viewDidUnload, release everything what can be reconstructed in viewDidLoad method later. It helps you to keep memory footprint as small as possible.
I am new iphone programming. Still if you think this useful then use it.
You can use tab bar for your MAIN MENU. When user click on particular tab , user gets list of menus relevant to that page. After this when user selects any menu then new view is pushed. So it will minimize number of views pushed by 2. In this way you can come back to same menu using back button.
If you take proper precautions while allocating & deallocating memory used then there will be no issues of memory consumptions.
The utility template is a good start, you can add more 'flipVeiws' or load the original 'flipView' with different content depending on which button is pressed on your 'homepage'. This content could come from a plist array etc.
You can use following code to find out how much memory is taken by ur app
struct task_basic_info info;
mach_msg_type_number_t size = sizeof(info);
kern_return_t kerr = task_info(mach_task_self(),
TASK_BASIC_INFO,
(task_info_t)&info,
&size);
if( kerr == KERN_SUCCESS ) {
NSLog(#"Memory in use Root(in bytes): %u", info.resident_size);
}
else {
//NSLog(#"Error with task_info(): %s", mach_error_string(kerr));
}
Also Use didReceiveMemoryWarning method to find out wheather your app is crossing memory limit