I made a simple flashcards HTML application and I experience strange problem with behavior under Android internet browser (default installation) on my Samsung Galaxy Tab2 7.0 tablet. When style of element is changed, such as
$(".question").css('color', '#FFFFFF')
$(".answer").css('color', '#FFFFFF')
$(".tag").css('background-color', '#FFFFFF')
the browser does not make any changes on display immediately. Later in code I am replacing text of containers and calculating sizes to fit text into element. I want this process to be invisible (that's why I want to do this white-on-white). I cannot hide elements, as then calculation would not work.
I have tested this under Windows 7 with Chrome and IE9 and it works great there. So there is some problem with the Android browser. When I put test code alert('debug'); behind the lines above, the Android browser shows message with no changes on colors on elements, but browsers under Windows 7 show message with white-on-white elements as expected.
How can I force Android browser to reflect such style changes immediately? Is there some script function available for that, or some <meta> tag that would fix this? Please advise.
When you say you want to "display style changes immediately" I'm guessing you mean that your script is going to continue to execute and you want the screen to update.
You need to use continuations. Rather than letting your script keep executing you need to yield and continue. You do this by breaking up your code into multiple functions and each piece finishes by setting a timeout for the next piece. Here's a simple example. When this is done with a loop, all the x's appear at once. When using continuations, one x appears at a time.
<html>
<script>
function using_a_loop() {
var e = document.getElementById('spot');
for (var i = 0; i < 1000; ++i) {
e.innerText += ' x';
}
}
function using_continuations(i) {
var e = document.getElementById('spot');
i = i || 0; // start at 0 when i not provided
e.innerText += ' x';
++i;
if (i < 1000) {
setTimeout(function() { using_continuations(i); }, 0);
}
}
</script>
<div id="spot">X marks the spot:</div>
<button onclick="using_a_loop()">use a loop</button>
<button onclick="using_continuations()">use continuations</button>
</html>
Related
I came across a situation were a button event handler calls a function, that may take a couple seconds to complete depending on the input. Once the function completes, the output will show up in a grid.
The function is completely client side. Right before the function is running I add a css class to the grid wrapper div that basically just shows a 'loading' gif/animation.
This works fine in Chrome, but not in Firefox and IE 11.
Below is an oversimplified version of how I achieve this with javascript setTimeout 0.
$('#calc').on('click', function(){
$('#container').addClass('loading');
calculate(10, function(res){
$('#result').text(res);
$('#container').removeClass('loading');
});
});
//represents my long running function
function fib(n) {
if(n<2) {
return n;
}
return fib(n-2) + fib(n-1);
}
//will be called by click handler
function calculate(n,cb) {
setTimeout(function(){
var result = fib(n);
return cb(result);
},0)
}
As you can see I use setTimeout 0 in calculate(n,cb) to give the browser the ability to show the 'loading' animation before the function starts and then remove it when it is done.
However, this does not work in Firefox.
What are some other options for me to achieve what I am trying to do?
I am using jQuery here, but the actual project I am working on is using Angular5. But the idea should be the same.
Here is a jsFiddle to show what I am trying to do. Using the loading animation by Mattln4D (thanks)
https://jsfiddle.net/alabianc/qL5zggh7/
If you want to see some actual good result, run it with 40 as an input in calculate, but no more than that!
I appreciate any help!
I think if you set the timeout = 0, it is so fast to browser can show the loading animation. When I try to change timeout = 10 or 100, I can see the loading animation show on both of chrome, ff.
I am new to JS, have a javascript code snippet below:
<script type="text/javascript">
var eatSteak = confirm ("Do you eat steak?");
if (eatSteak) {
document.write("Here's a Steak!");
}else{
document.write("Here's a Tofo!");
}
var happy = prompt ("Are you happy?");
</script>
When I debug the code in chrome, I see after give yes to confirm pop-up. It hits the code "document.write("Here's a Steak!");", and HTML page display "Here's a Steak!", then code hit prompt pop-up.
Very confusing for me is when I run it in chrome, "Here's a Steak!" will only display after prompt pop-up. Seems document.write only take effects after javascript code execution? Or HTML start rendering the page after javascript? I googled but cannot find a similar question or answer.
It is the nature of a single threaded javascript model. As a prompt, alert, etc stops the execution until you make a decision, any of the DOM manipulations you made before, wait until you are out of the current scope. This can be different in different browsers, but that depends on how DOM manipulation is implemented.
The following script below would block the red color until you click OK (at least on Chrome, on Firefox I was suprised to see it didn't work :D)
The setColor to green does the manipulation and then starts a timer to show the alert at the next possible time using setTimeout. This will make sure green is set before the alert is shown (in any browser)
// blocking call until it exits the function (at least, on Chrome, firefox seems to work)
function setColorToRed() {
document.body.style.background = 'red';
alert('Red will come after ok');
}
// none blocking call, works on all browsers
function setColorToGreen() {
document.body.style.background = 'green';
setTimeout(function() {
alert('Green color should have been set');
}, 0);
}
<button type="button" onclick="setColorToRed()">Blocking call red</button>
<button type="button" onclick="setColorToGreen()">None blocking call green</button>
I'm using the svg4everybody and I don't understand why sometimes it freezes the mouse interacions.
The plugin is loaded in many iframes dynamically, but only some times it freezes.
If I hover on buttons and other clickable elements the cursor changes and if i press the back button the site goes back and the freeze disappear.
Looking in the source file I see that the requestAnimationFrame function is used:
function onframe() {
var use;
while ((use = uses[0])) {
// some code
}
requestAnimationFrame(onframe);
}
if (IE9TO11) { // <-- edited in tests with if ( true || IE9TO11 )
onframe();
}
It is possible that it's the requestAnimationFrame that make the freeze? Or someone has another better idea?
NOTE: it freezes only in IE11. Tried in FF32 and Chrome 39 and works without problems
I'm using an application that does two steps during a jquery click event.
1. Changes the CSS properties of an element with a sprite and color attribute
2. Runs a function that iterates scanning the page.
Is it possible to have the page make the css changes and show it in the browser, then run the iteration?
The css changes are made by adding classes and removing classes to the elements.
onBtn.click(function(event){
if(clicked['mon'] == 0){
monBtn.attr("class", "active");
clicked['mon'] = 1;
dow['mon'] = 1;
}
else {
monBtn.removeClass("active");
clicked['mon'] = 0;
dow['mon'] = 0;
}
checkIfButtonsAreClicked();
});
If you're looking for the screen to update before running some other code, you could set the code to fire in 0ms:
makeCSSChanges();
setTimeout(function () {
// The browser will only run this callback once it's taken a breath and
// done its usual behind-the-scenes stuff.
scanThePage();
}, 0);
When a timeout is set for 0ms, most browsers will do their usual behavior (redraw the page, go about their business, etc.), then take care of scheduled events.
In most cases, though, the delay wouldn't be noticeable enough to matter. If the delay is significant, then we're approaching the kind of delay that can also lag out the whole browser. Careful.
Here is the situation. I have some javascript that looks like this:
function onSubmit() {
doSomeStuff();
someSpan.style.display="block";
otherSpan.style.display="none";
return doLongRunningOperation;
}
When I make this a form submit action, and run it from a non IE browser, it quickly swaps the two spans visibility and run the long javascript operation. If I do this in IE it does not do the swap until after onSubmit() completely returns.
I can force a dom redraw by sticking an alert box in like so:
function onSubmit() {
doSomeStuff();
someSpan.style.display="block";
otherSpan.style.display="none";
alert("refresh forced");
return doLongRunningOperation;
}
Also, the obvious jquery refactoring does not affect the IE behavior:
function onSubmit() {
doSomeStuff();
$("#someSpan").show();
$("#otherSpan").hide();
return doLongRunningOperation;
}
This behavior exists on IE8 and IE6. Is there anyway to force a redraw of the DOM in these browsers?
Mozilla (maybe IE as well) will cache/delay executing changes to the DOM which affect display, so that it can calculate all the changes at once instead of repeatedly after each and every statement.
To force an update (to force an immediate, synchronous reflow or relayout), your javascript should read a property that's affected by the change, e.g. the location of someSpan and otherSpan.
(This Mozilla implementation detail is mentioned in the video Faster HTML and CSS: Layout Engine Internals for Web Developers.)
To continue what ChrisW says:
here's flushing script to flash DOM, so you don't have to call alert(""); (found at http://amolnw.wordpress.com/category/programming/javascript/):
function flushThis(id){
var msie = 'Microsoft Internet Explorer';
var tmp = 0;
var elementOnShow = document.getElementById(id);
if (navigator.appName == msie){
tmp = elementOnShow.parentNode.offsetTop + 'px';
}else{
tmp = elementOnShow.offsetTop;
}
}
It works for me!!!
Thanks for the tip.
I had this problem in Chrome 21 dragging a word that had a letter with a descender ('g'). It was leaving a trail of moth dust behind on the screen, which would vanish the next time something made the screen refresh. ChrisW's solution (interrogating a layout-sensitive property) didn't work.
What did work was to add a 1-pixel blank div at the top of the page, then remove it a millisecond later, by calling the following the function at the end of the drag operation:
// Needed by Chrome, as of Release 21. Triggers a screen refresh, removing drag garbage.
function cleanDisplay() {
var c = document.createElement('div');
c.innerHTML = 'x';
c.style.visibility = 'hidden';
c.style.height = '1px';
document.body.insertBefore(c, document.body.firstChild);
window.setTimeout(function() {document.body.removeChild(c)}, 1);
}
Note: You need the delay. Simply adding and removing the div doesn't work. Also, the div needs to be added above the part of the page that needs to be redrawn.
You can also wrap you longterm function in a setTimeout(function(){longTerm();},1);
Can your longRunningOperation be called asynchronously?
element.focus() works for me in IE10
function displayOnOff(){
var elm = document.getElementById("myDiv");
elm.style.display="block";
elm.focus();
for(var i=0; i<1000000; i++){
console.log("waiting...............");
}
elm.style.display = "none";
}