I have a set of functions, and I want to do something, like show a loading animation, while these functions are running! and when they stop i want to show an alert, for example.
All this on jQuery.
Anyone has a tip?
Some abstract code:
//these are my functions:
function a(number){number=number*2};
a(1); a(2); a(3);
//While this functions are running i want to show a gif, for example!
//When the three callings this function has done, i want to show an alert
Your JavaScript is executed in the same single thread as all other rendering within the document and it is therefore pointless to make a UI change before running a lot of synchronous JS (your functions) only to then reverse the UI change. The UI will remain the same to the user.
Doing what you want would only be useful in situations where asynchronous requests are occurring, and in such situations you would have to rely on callback functions.
Like this:
// code to show loading message
function a(number){number=number*2};
a(1); a(2); a(3);
// code to hide loading message
The code is executed from top to bottom, so by the time function are running, the loading message will be showing because it is before those functions and when functions are done, it will hide again.
just before the call to the function display some animation gif on the screen
and just after the call the function remove it and show your alert.
thats it.
Related
I'm having a hard time even asking this question because I don't understand what is going on.
Basically, I have a spinning loader element that should be displayed while my javascript runs. At the end of the javascript the loader should be turned off and a modal should be displayed with data queried from a database. The problem is that the loader is never displayed. Theres about a 1 - 2 second wait while the queries run before the modal is created.
function includeConnectionJS() {
if (!(typeof sforce === "object")) {
var connectionJS = document.createElement('script');
var documentHead = document.getElementsByTagName('head')[0];
connectionJS.src = '/soap/ajax/38.0/connection.js';
connectionJS.setAttribute('onload', 'createLoader();createModal();');
documentHead.appendChild(connectionJS);
} else {
createLoader();
// Checks to see if the loader element exists. If it does not, create the element and than toggle it to display it.
// If the element already exists, display the modal
createModal();
// Checks to see if the modal element exists, if it does not, create the element and than turn off the loader and display the modal.
// If the element already exists, turn off the loader and display the modal
}
}
I put console.logs in my methods and I can clearly see that the method is being called, the if statements are all passing and the visibility of the element is changing to the correct values at the correct times. Everything seems to imply that it should be working, but the element is never actually displayed.
I was able to get it to display by changing the call to createModal to look like the following:
setTimeout(function(){createModal()}, 100); // Most values for delay worked.
I don't want to create an artificial delay just to show loader for effect.
My primary concern is that the createModal method makes calls to the database. These cause delays in the javascript execution (I call them synchronously, not asynchronously). I can clearly see the loader display being set to 'block' before the queries, watch all the queries call out and return and see the display of the loader change back to 'none' all in the correct order. More than that, if I call the createLoader(); method directly from the console, it works.
I just can't figure out what it is I'm missing.
With synchronous Javascript calls you are blocking the UI and other functions queued in the Event Loop https://developer.mozilla.org/en/docs/Web/JavaScript/EventLoop#Run-to-completion. It's important to remember that Javascript code executes in a single-thread. So no code can execute in parallel, everything else has to wait until the current task is done. In practice this means that you want your functions to do their job as quickly as possible so that other operations (UI updates, keyboard/mouse events etc., timeouts, or asynchronous callbacks etc.) can execute. They all have to wait until you pass back control to the engine through completing the current code block.
setTimeout works because it adds the long running createModal function to the Event Queue for execution sometime in the future (even when set to 0ms - it doesn't guarantee immediate execution it just says at first opportunity you can sometime after 0ms has elapsed. If you have a long running function that might actually be 10s later). Doing this allows the calling function to complete quickly and the UI is now able to apply any updates. Now when the javascript engine is ready to run further code it will look for the next block of code recorded in the Event Loop. This time when it runs createModal it will again block updates to the UI etc., handing mouse & keyboard events etc., but now the UI has had the opportunity to update, you'll have your spinner up.
So the choices are: either use asynchronous calls in your function so that it completes quickly, or if that's not possible continue using setTimeout() to queue the long running task after the UI has updated.
I'm trying to understand why this works the way it does. I'm under the impression that the alert dialog blocks script execution. Yet the script is behaving as if execution continues behind the scenes, without updating the screen.
Take this code:
function highlightItems(itemA, itemB, msg) {
$(itemA).effect("highlight", {}, 800);
window.alert(msg);
// $(itemB).delay(1);
$(itemB).effect("highlight", {}, 800);
}
When I close the alert dialog, the highlight effect for itemB is already done. (If I close the alert quickly enough I can catch the tail end of the effect.) It's as if the effect started before I got a chance to close the alert box.
All I can think of is that whatever effect() is using to time itself is being thrown off by the call to alert(). If I un-comment the .delay, the highlight works as expected: it begins immediately after the alert box is closed. So would that mean the .delay function "resets" the effect timer?
This isn't a major problem... I'm just trying to understand what's going on here. My usual Google skills have failed me today.
Edit -- jsfiddle for an example of what I mean: jsfiddle.net/kA2uV/
Edit 2
This apparently only affects cases where the same .effect is used twice in a row. If a different effect is used, the problem doesn't happen: jsfiddle.net/yXSgu/3/
IIRC, jQuery animations are based on the date/time, it isn't handled primarily by setTimeout or setInterval. Time keeps on going while the javascript is halted.
Edit: I see what you mean, though i still think it has to do with date/time, maybe jQuery's internal use of $.now() in this case IS being thrown off by the alert coupled with the .delay(1)
The alert function "pauses" the state of the program, so that when it's dismissed, the program will resume. the delay should come after the alert to assure that you are not waiting longer than intended.
That's because highlight fires, but the alert doesn't wait for it to finish before launching.
Here is a modified version that works as expected. (the highlight finishes before the alert shows)
Additonally, your example doesn't 'pause' the highlight because as another poster has said, jQuery uses time values to run animations.
http://jsfiddle.net/yXSgu/
Is JavaScript intended to be running as little as possible on a website/webapp? By that I mean is the usual intention to run through all your js files as soon as the page loads and put them aside, and then when functions come up to execute them right away and be done with it?
I'm working on a project using google maps and I have a custom marker object scripted out, and a debugger has told me that the browser runs through all my js files before anything even appears on the page.
My problem comes in here: I wanted to animate certain markers to bounce up and down continuously with jQuery (similar to OS X icons in the dock) and my several attempts at infinite loop functions all just crash the browser. So I understand that the browser doesn't like that, but is there a way to have a simple script be repeating itself in the background while the user navigates the page? Or is JavaScript just not supposed to be used that way?
(I worked with Flash for a long time so my mindset is still there.)
Yes, Javascript functions should just do their bit and exit as soon as possible. The GUI and the scripts run on the same single thread, so as long as you are inside a Javascript function, nothing shows up in the browser. If you try to use an infinite loop, the browser will appear to freeze.
You use the window.setInterval and window.setTimeout methods to trigger code that runs at a specific time. By running an interval that updates something several times a second, you can create an animation.
You have to set a timer to execute a script after a defined time.
var timer = setTimeout(code, milliseconds);
will execute code in so-and-so milliseconds. Each execution of the script can set a new timer to execute the script again.
You can cancel a timed event using clearTimeout(timer).
Use setTimeout() or setInterval(). The MDC articles on it are pretty good.
You'll need to update inside of functions that run quickly, but get called many times, instead of updating inside of a loop.
Since you said that you are using jQuery, consider using its effects API (e.g., jQuery.animate()), it will make your life much easier!
Personally, I save as much code as possible for execution after the page has loaded, partly by putting all my <script>s at the bottom of <body>. This means a (perceived) reduction in page load time, whilst having all my JS ready to run when need be.
I wouldn't recommend going through everything you need to do at the beginning of the document. Instead, bind things to events such as clicks of buttons, etc.
I'm probably missing something really obvious here...
I'm showing a dialog box with progress bar during page load. The dialog and progress bar are both jQueryUI widgets. There are a couple of phases of loading - the page makes a load of jQuery $.get() requests to load resources, then on the $(document).ajaxStop() event, does things with those resources. I'm updating the progress bar and some status text throughout this process.
The issue is that as soon as the ajaxStop event fires, updates stop. The code works nicely during resource loading, but then freezes and I don't see any of the updates during processing. If I put a breakpoint on a post-ajaxStop update in Chrome and step through the code, the screen updates correctly so I know that the code works.
Can anyone explain why everything updates nicely during my AJAX loading phase, but then stops on the ajaxStop event? Is there an easy way to make updates continue afterwards?
Thanks!
Several hours of searching later, the following blog pointed me in the right direction:
There's a jQuery extension described in the entry which allows you to define two functions, one to compute and one to update the UI. It schedules them alternately using the setTimeout function.
I've had to rewrite my code in something akin to continuation passing style so that each function schedules its continuation to run using setTimeout. This returns control to the browser for long enough for the screen to be updated.
This feels like a bit of a hack though to get round browser/Javascript limitations. Anyone know of a better way?
I have a page that loads a bunch of scripts to prepopulate dropdowns and has scripts within the html onclick events and etc.
After the page loads and I open the page in the script console I can't do anything. everything is null and functions non-existent.
For example there is an onClick function onclick="Popup('Seattle');".
If I try to invoke that from the script console I get Object Expected error like it doesn't even exist. But if I click the button the method fires right up. I can't modify this code so it's important that I get this functions going.
While I'm stepping through the code and have the script paused I have access to everything but as soon as it's finished it's back to nothing at all.
Anyone know what's going on and is there a way to invoke these functions?
"Object expected" sounds like for example the Popup function wants to be called like Popup.call(somedomnode, args...). When called from an event handler, this is set to the element the handler is called on. If you just try to call it without some object as this, it might complain.
Otherwise probably the functions you want to call are not in scope at top-level. You don't really tell us how these functions are defined or how the event handlers get set up, so it's hard to say more where the problem might be.