DOM is asynchronous with javascript? - javascript

I observed number of instruction counts executed on cpu while running javascript tests on Android browser.
The test js codes are simple in html. The files are in android local directory, not in webserver.
In html:
<html>
<head>
<script type='text/javascript' src='test.js'>
</head>
<body>
<div id='content'> ... </div>
<span> .. </span>
<div id='logo'> ... </div>
...
</body>
</html>
In test.js:
for (i = 0; i < 1000 ; i++) {
...
$().append("<div id='content2'> ... </div>
var temp1 = $(span#content2)
var temp2 = $(#logo)
var temp3 = $(h3.id)
...
}
In a nutshell, in test.js, simple methods such as .append() using jQuery are used.
When I run this simple test code on Android browser, I think I should have consistent number of the instructions, but, actually, I have various instruction counts in each run.
It may have some pattern in the variation, but, not seem clear.
My initial guess was an "asynchronous" thing in DOM in html with javascript.
So, I changed the html like this:
<html>
<head>
</head>
<body>
<div id='content'> ... </div>
<span> .. </span>
<div id=''> ... </div?
...
</body>
<script type='text/javascript' src='test.js'>
</html>
Also, I tried this
$(document).ready(function() {
...
$().append("<div id='content2'> ... </div>
var temp1 = $(span#content2)
var temp2 = $(#logo)
...
});
But, I didn't get consistent number of instructions yet.
This is caused by asynchronous problem? Or jQuery methods in terms of DOM have kinda indeterministic behavior in run time? Or, JS JIT compiler has very different behavior in each run? Can anyone give me some clue?
Thanks!

It's not just that JavaScript does not run synchronously with DOM rendering, it's that HTML parsing itself is inherently loose, and was never designed to be deterministic. "Good enough" is what got JavaScript and HTML to where every device and its brother can use them, but the price paid for that is some level of unpredictability.
In general, don't use HTML parsing if you don't have to, especially if you want consistent performance. The DOM has a perfectly serviceable createElement method that you can send to jQuery's append method, which will likely get you more consistent results. (And it's not like insertBefore is all that hard a method to use. If you're taking the time to measure CPU cycles, you're doing a level of work significantly greater than jQuery's target model.)
(And I'd be very surprised if a JIT compiler didn't give you different results over a large enough test run. Unless you manage to have exactly the same device each time, I'd expect some variation based on the available input variables it would have to use to judge how much compilation to do, such as memory allotment and CPU load.)

Related

Cordova freeze UI during long Javascript while

I can't create a working example, but the code is simple.
Configuration
IDE: Visual studio 2017
Target platform: Windows x64
System: Win 10
My project: Javascript // Blank App (Apache Cordova) // ver. 6.3.1
HTML // index.html
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<header></header>
<main>
<div id="cal">
</div>
</main>
<footer>
<!-- ## this creates a simple pure css loader ## -->
<div class="progress">
<div class="indeterminate"></div>
</div>
Add
</footer>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="scripts/platformOverrides.js"></script>
<script src="frameworks/jquery-3.2.1.min.js"></script>
<script src="frameworks/materialize/js/materialize.min.js"></script>
<script type="text/javascript" src="scripts/index.js"></script>
</body>
</html>
Javascript // index.js
(function () {
"use strict";
document.addEventListener( 'deviceready', onDeviceReady.bind( this ), false );
function onDeviceReady() {
$(document).ready(function () {
$('.addItem').on('click', function () {
setTimeout(function () {
loadCalendar();
}, 5000);
});
});
};
function loadCalendar() {
var i=0;
while (i <= 10000) {
var html = '<div class="row"></div>';
$('#cal').append(html);
i++;
}
}
} )();
App starts and the UI work as expected, the progress loader show his css animation. After clicked the button addItem all work for 5 seconds and then the UI freez until the while loop end. I don't think it is normal, how can I solve it ?
Thanks
Edit
An important clarification
I don't expect the DOM to be updated during the loop, and this code above is not the real code, it is only usefull for understanding and test. The real loop is much shorter and faster, but it is still a problem.
What happens is that the whole interface freezes, the whole app. The CSS animation should be totally independent from Javascript, but is freezes!
Here an example of what I expected
I hope this clarify the point better.
As stated in the comment, all loop declarations are blockers, and before the loop has finished - even the most trivial hover effect will not be able to respond.
JavaScript is linear, synchronous and a single-threaded process. To circumvent the freeze condition, you will need to move your loop operation on to a separate thread.
E.g.: On another - separate instance, of a document!
I think this is to be expected. You're calling $('#cal').append(html) 10,001 times. Each time you do this you're modifying the DOM which is an expensive operation.
If you really need to write out 10001 div class='row' elements you might be better off writing them all to a string then doing one append. It's still not ideal but it's hard to see a better solution without knowing more about what you're trying to achieve.
function loadCalendar() {
var i=0;
var html = '';
while (i <= 10000) {
html += '<div class="row"></div>';
i++;
}
$('#cal').append(html);
}

Unbalanced tree - JS Error

I am developing an application that uses loops to create a desired output; here from number 1 to 50. I am using a for loop and uses the concatenation method to show the looped numbers. But then the debugger in the browser is saying that I have written an unbalanced tree.
Here is the error:
An unbalanced tree was written using document.write() causing data from the network to be reparsed. For more information https://developer.mozilla.org/en/Optimizing_Your_Pages_for_Speculative_Parsing
Here is the code:
<script type="text/javascript">
for(i=1;i<=50;i++){
document.write(""+i+"");
}
</script>
Note: The links I am creating use an id attribute to link somewhere exactly on the page.
Thanks for help.
It's a warning. It happens in Firefox 4 and later.
From MDN: Optimizing your pages for speculative parsing:
However, in Firefox 4 and later the HTML parser also runs the HTML tree construction algorithm speculatively. The upside is that when a speculation succeeds, there's no need to reparse the part of the incoming file that was already scanned for scripts, style sheets and images. The downside is that there's more work lost when the speculation fails.
[...]
Speculative tree building fails when document.write() changes the tree builder state such that the speculative state after the </script> tag no longer holds when all the content inserted by document.write() has been parsed. However, only unusual uses of document.write() cause trouble. Here are the things to avoid:
[...]
Don't write unbalanced trees. <script>document.write("<div>");</script> is bad. <script>document.write("<div></div>");</script> is OK.
The solution is to write the missing single closing quote.
<script type="text/javascript">
for(i=1;i<=50;i++){
document.write("<a href='page.html#"+i+"'>"+i+"</a>");
}
</script>
You have missed out an single quotes.
Try running with below:
for(i=1;i<=50;i++){
document.write("<a href='page.html#"+i+"'>"+i+"</a><br/>");
}
Be careful while using single and double quotes.
Even if you document.write(...) a balanced tree, for example document.write('<span>X</span>'), then you still can get the same error message.
One possible explanation is that you execute that JS code not in the body but in the head of the html, writing something that cannot occur in the head.
For example:
Wrong:
<html>
<meta charset="UTF-8">
<script>
document.write('<span>X</span>');
</script>
</html>
Good:
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<script>
document.write('<span>X</span>');
</script>
</body>
</html>

What is the distinction between head.ready() and head.load()?

Using the JS loader head.js I'm having a bit of a hard time distinguishing the subtle differences between head.ready() and head.load().
head.ready('jquery.js', function(){//Do something});
VS
head.load('jquery.js', function(){//Do something});
As far as I understand both seem to load 'jquery.js' and then perform a callback when it is loaded. However, in practice I get some edge cases where head.load doesn't work as expected in Firefox making me think I am not understanding where to use head.load and where to use head.ready.
Reading the API it seems like head.load loads the content, but head.ready is an Event Listener, you can also add a callback to head.load and would work too, but head.load is the only one who can actually load the resources, head.ready not.
EDIT: An example
<html>
<head>
<script src="head.min.js"></script>
<script>
// this loads jquery asyncrounously & in parallel
head.load("jquery.min.js");
</script>
</head>
<body>
<!-- some content-->
<!-- injected via a module or an include -->
<script>
// some function that depends on jquery
head.ready("jquery.min.js", function () {
// this will only be executed once jquery has finished loading
$(".main").hide();
});
</script>
<!-- some content-->
</body>
</html>

Best way to fire events when single elements in the document becomes ready

I'm developing a web application that because of performance concerns is heavily reliant on Ajax functionality. I'm attempting to make parts of each page available while longer running modules load.
The issue is that I want to kick off the Ajax requests as soon as possible (in the head of the document). This part works fine; the issue is on rare occasion, the Ajax call will come back before the area that I want to load the Ajax data into is present on the page. This causes the data to not be loaded.
To get around the issue I started using script tags below each of my containers that resolve a JQuery promise to let the code know that the area is available.
EDIT: I want to load the data into the area as soon as it becomes available (before full document load).
The current pseudo code looks like this:
<head>
<script>
var areaAvailablePromise = new $.Deferred();
$.when(areaAvailablePromise, myAjaxFunction()).then(function(){
// load data into the element.
});
</script>
</head>
<!-- much later in the document -->
<div class="divIWantToLoadAjaxContentInto"></div>
<script>
areaAvailablePromise.resolve();
</script>
My question is: is there ANY better way to handle this situation? Every one knows that inline scripts are blocking and are bad for performance. Also, I feel that this is going to lead to cluttered code with micro-script tags all over the place.
Put your (whole) <script> tag just after the element.
HTML is parsed from top to bottom, so the element will be loaded already.
No. There really is no better way to my knowledge.
<!doctype html>
<html>
<head>
<script src="jquery.min.js"></script>
<script src="q.min.js"></script>
<script>
var elD = Q.defer();
var dataP = Q($.ajax(…));
Q.spread([elD.promise, dataP], function (el, data) {
…
}).done();
</script>
</head>
<body>
…
<div id="foo"></div>
<script>elD.resolve($("#foo"));</script>
…
</body>
</html>
you can use:
$(document).ready( handler )
(recommended)and also has contracted form:
$(handler)
exemple:
$(function(){
alert("OK");
})
read more: http://api.jquery.com/ready/

alternating headers and function call

I'm trying to create this webpage for homework where I have to state which function I'm testing and give the result after. For example:
"Testing function1" --> should be a heading (h1....h6)
result
"Testing function2"
result1
...
According to the homework rules, i have to put my javascript code in head and call the functions in body.
I tried thinking of a way where I don't need to re-type
<script type="text/javascript"> </script>
a few times. Any ideas?
There's nothing wrong with having <script.../script> a few times, if that's the order it appears in the page. You don't need to group all your scripts into one <script> tag for neatness or anything.
It's pretty common to see a block of HTML then a <script> after it which does something relating to that HTML (bad practice yes, but not something to worry about just yet when you're learning).
Unless there's something specifically saying you can't use more than one inline script, I'd just say make it easy for yourself.
You could use some document.writes if you really wanted to, or something along those lines (.innerHTML is another option) but that'll just generate messier code. Keep your HTML as HTML, and where possible, don't write Javascript that creates HTML.
All in one:
<script type="text/javascript">
document.write('<h1>Testing f1()</h1><p>' + function1() + '</p><h1>Testing f2()</h1><p>' + function2() + '</p>');
</script>
Yes it's one line, but damn, how annoying would that be to debug if it was something a little more complex?
My recommendation:
<h1>Testing f1()</h1>
<p>
<script type="text/javascript">
function1();
</script>
</p>
<h1>Testing f2()</h1>
<p>
<script type="text/javascript">
function2();
</script>
</p>
Yes it's more lines, but it's much easier to see what it's doing at a glance - you don't need to actually read it, it's very very obvious.

Categories