Cordova freeze UI during long Javascript while - javascript

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);
}

Related

Javascript - ajax refreshing a div with an old version of an updated file

I am making a web dashboard and for this I have a javascript function that loops infinitely, updating a particular div at frequent intervals. (it uses ajax/jquery to do this).
I have used a loop with setTimeout:
<!doctype html>
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
<script type="text/javascript" language="javascript">
function updateMain() {
setTimeout(function() {
console.log("updating");
$('#main').load('new-content.php #main', function() {});
updateMain();
}, 3000)
}
updateMain();
</script>
</head>
<body>
<div id="main">
<p>hi there</p>
</div>
</body>
</html>
'new-content.php' is a file that is constantly updated by another part of my program, to show the new content for the dashboard.
it looks something like this:
<div id="main">
<p>Hello i am updated content</p>
</div>
I am sure the loop is working as the "updating" messages appear at regular intervals in the console.
When the program starts, the div is showing "hello there", and in the new-content.php file it has "hello am updated content".
The first time the loop runs, it updates the div to show "hello i am updated content".
But if I further update the new-content.php file, for example to say "hello I am further updated content", it just won't show on my webpage. However I am sure that the loop is still running as the messages appear in console.
It's like ajax has some cached version of the new-content.php file that it loads at the start then keeps using forever.
I am very confused, if you could help me I would be very grateful
Thank you
PS: if it is of relevance, the website is running through flask but I don't think this is the problem.
EDIT: I believe it is actually a flask caching issue
You can try adding a cache buster to see if that helps. Change your code as follows:
function updateMain() {
setTimeout(function() {
console.log("updating");
const cb = new Date().getTime();
$('#main').load('new-content.php?cb=' + cb + '#main',function() {
updateMain();
});
}, 3000)
}
updateMain();
Wasn't able to solve the issue but for anyone who is trying to make a similar project, I decided to use flask-socketio instead which allows me to send data to javascript to be shown on the page, instead of javascript loading the data itself from a file. (the answer by vladtn on this SO post was useful as an introduction to socketio)

DOMReady: 'kendo' is undefined

I am receiving an intermittent error from JavaScript in my production environment and was hoping to learn more about the loading process.
The error is simple enough to understand:
'kendo' is undefined.
It states that the kendo variable is undefined at a time that I try to use it. However, I have all of my JavaScript code wrapped inside a jQuery ready event, like so...
<head>
<script src="path/to/jQuery.js"></script>
</head>
<body>
<!-- ... -->
<script>
jQuery(function ($) {
var test = new kendo.data.DataSource({
// datasource options
});
});
</script>
<!-- ... -->
<script src="path/to/kendo.js"></script>
</body>
I was under the impression that doing jQuery(function() { ... }); would cause the inner code to run after the DOM is ready and that it would run only after all of the <script> tags have been parsed and processed.
Is this not the case? Should I be adding my code to the loaded event instead of the ready event?
FWIW, we are using Cloudflare to handle minifying and caching, and the intermittent behavior seems to only be related to IE. I can't replicate the problem, though, I just get notified when one of our pages fails to finish loading and I see the console has this undefined error. Navigating to the page again yields no problem, so I'm a little baffled. Any ideas?
Also, I don't see any duplicate references to the jQuery or kendo libraries in my code.
Use it this way ...
<head>
<script src="path/to/jQuery.js"></script>
</head>
<body>
<!-- ... -->
<script src="path/to/kendo.js"></script>
<script>
jQuery(function() {
var test = new kendo.data.DataSource({
// datasource options
});
});
</script>
<!-- ... -->
</body>

Best way to access external JavaScript file and place contents in div?

So, lets say you have a page that wants to load from a javascript file and it includes
temp.html file
<script src="example.js"></script>
<p class="one"></p>
Now in the example.js file you have a function that is
function getInfo() {
var place = "foo"
$(".one").html(place);
}
//Edit currently I call the function inside the JS file
getInfo();
My question is how would you connect the two files so that the external javascript file knows that it is pointed to the paragraph with the class one?
Normally when this is in a single page, you would call the function and the info will be set.
I have seen a getScript method and a load method for Jquery. Would that be applicable here?
Any ideas on how to approach this? If you provide some code that will be super helpful.
Thanks in advance.
Looks like you want to execute getInfo() as soon as it's defined (i.e.: example.js is loaded).
You can try this approach:
<script src="example.js" onload="getInfo();"></script>
In your example.js, change getInfo() to something like this:
function getInfo() {
$(document).ready(function() {
var place = "foo"
$(".one").html(place);
});
}
Your language is confusing, but you could use jQuery's $(document).ready function which would suffice. Generally speaking, an externally loaded file should execute where the tag is in the script.
A hack could be to place a tag before the end of your document body, give it an id, and then use $('#id').ready() there. In general though, you could just try coding the transclusion concept (I'm guessing you're used to this) from scratch using intervals and timeouts.
<div id="rdy">
</div>
</body>
Then in your file:
$('#rdy').ready(getInfo);
Just my added opinion, you should consider that Google is up to some not-so-nice things these days, they are long-gone from the "do no evil" mantra.
If we assume you have a JavaScript file that contains this content:
function getInfo() {
var place = "foo"
$(".one").html(place);
}
then your markup will look something like this:
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="example.js"></script>
<script>
$(function(){
getInfo();
});
</script>
</head>
<body>
<p class="one"></p>
</body>
</html>
$(function(){ ... }); is just the simplified version of $(document).ready(function(){ ... });. They both more or less handle the onload event, which fires when page has finished loading.

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/

DOM is asynchronous with 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.)

Categories