I'm trying to show a popup in the middle of the screen while my website talks to my AJAX server. Since some of the operations take a couple seconds to do, I want to give my users a visual cue that an operation is occurring. For example, you can create a music playlist on my site. When the playlist is being created, I want a div to popup saying it's creating the playlist on my servers.
I made a jsfiddle to show the functions I'm using to try to produce this, but I'm having a bit of an opposite effect. In the fiddle, it shows the popup after it tries to talk to the server (it will fail to talk to the server because I deny anything outside my domain), but since it fails to talk to the sever, it never calls hide_popup().
On my servers, it never even shows the popup (unless I call an alert() directly after the show_popup() call).
I'm not sure why this happens, but I simply want to
1. Show the popup
2. Execute my AJAX-call
3. Hide the popup
Any suggestions?
There are a few problems with the way you wrote your code. Here are a couple of them:
(1.) Call:
var response = get_server_response("action=createPlaylist&name=" + name, false);
You are expecting a response immediately which will not happen with an AJAX call. Moreover, you are passing false for the async parameter, which is making it effectively a sync call. This is why your code is just waiting before doing anything else.
(2.) Implementation:
xmlhttp.onreadystatechange = function()
{
if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
response = xmlhttp.responseText;
}
}
xmlhttp.open("POST", ajax_server, async);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send(url);
return response;
You are only caching the result in response and not processing it while tracking onreadystatechange. You are actually processing it just after the call which will execute after the call and not on receiving the response. No need to return the response here.
(3.) popup:
You are not using show/hide at an appropriate place.
Solution:
I would suggest you fire a callback while tracking the onreadystatechange by implementing a function. Show the popup just before you make the network call. Hide it inside your callback function depending on the readyState and status.
Here is a working fiddle for you: http://jsfiddle.net/nDNXc/549/
Hope that helps.
First I recommend you to use a common library for your Ajax calls, e.g. jQuery.ajax.
Second learn about asynchronous Javascript. Your call of get_server_response() returns immediately without waiting for your Ajax request to complete. Have a look at the complete parameter in jQuery.ajax. It accepts a function that is called when your requests completes - the right place to hide your message!
Related
I have a server function like this
function very_long_task($data) {}
This function is called using $.ajax() function clients-side.
The problem is that when my server-side function very_long_task() is executed the site is locked down. Meaning that if I tried to view another page of the website from a different tab or window, the website will not load until the very_long_task() function has completed.
Is there anyway to get around this either server-side or client-side?
UPDATED: 2015-11-3
The AJAX call is actually called many times because it is looping through all the elements in a list and performing an action on each of them. The very_long_task() function is then being called on each element.
For example, if there were a list of 20 elements then the very_long_task() function would be called 20 times. This does help a little bit in the overall responsiveness on that page but not on other pages.
UPDATED: 2015-11-3
Also this is built with WordPress so I can leverage some of their functions, but I have had no luck with wp_schedule_single_event since I need a return value.
https://codex.wordpress.org/Function_Reference/wp_schedule_single_event
UPDATED: 2015-11-3
Here is an updated view of my
function very_long_task($data) {
session_write_close();
// Very long task...
return $data;
}
You'll want to call session_write_close() as soon as possible.
This is because while one page has called session_start(), the session file will be locked until the page finishes execution, or until the session is closed.
If this is not done, any page calling session_start() will wait for the lock to be lifted.
UPDATE
I think I know what's going on:
your browser limits the number of simultaneous connections to a server, typically somewhere between 2 and 10.
If you're making 20 asynchronous AJAX calls, and you open the Developer Console (F12 / control-shift-I), you'll probably find that not all of them are executing simultaneously. This would certainly leave no room for additional connections.
Note, that the session_write_close() is still necessary, otherwise the ajax calls will execute serially.
SUGGESTION
So, it is best to only make one AJAX call.
If you want parallelism, you can fork child processes server-side.
You probably won't be able to use jQuery for this, because you'll want to send data from the server and flush()-ing it as it becomes available (HTTP streaming).
One solution I used in a WP importer plugin is not to use AJAX at all, but perform the long running operation, pushing out HTML and a <script> tag to update the UI.
I'm not entirely sure what you mean by "locked down" but below are some things to try:
Make sure that your AJAX is asynchronous
$.ajax({
url: '/start_very_long_task.php',
async: true
});
Make sure your PHP accommodates the expected behavior
// start_very_long_task.php
function start_very_long_task()
{
ini_set('ignore_user_abort','on');
ini_set('max_execution_time', 0)
session_write_close();
do_very_long_task();
}
function do_very_long_task()
{
// Very long task stuff
// This can recursively call itself without making
// making multiple calls to session_write_close(), etc...
}
start_very_long_task();
I'm not sure if what I'm about to ask is possible or the right way of doing about things, but here goes.
I have a webpage which loads some data from a server using AJAX and displays it visually. The user has the option of using one of two buttons on the page to "scroll" through the data which is filtered by week.
The code for these buttons is something like:
$("#leftButton").click(function () {
clearCurrentlyDisplayedData();
changeFilter(1); //Or -1, or whatever.
loadAndDisplayData();
}
In this (simplified) example, loadAndDisplayData() would use AJAX calls to fetch this data and then display it on completion of the request, like:
$.get(
"web/service/address",
function (data, textStatus, jqXHR) {
//Display the data here
});
However, there is a problem when the user clicks the arrows to scroll through the data too quickly. If the buttons are clicked twice in quick succession, the data for two weeks is displayed, on top of each other.
I don't want to disable the buttons until the data is collected - since the data collection and displaying does take a little bit of time, this would kill the ability of the user to navigate through the site quickly, and would quickly become irritating.
Is it possible to kill any currently executing scripts or AJAX calls (or functions called as a result of these) when the user clicks on one of the buttons in order to prevent the loading of two sets of data? Is there any other way I can go about solving this problem?
The jqXHR object has an abort() method, which you can call to cancel an AJAX request.
However, this requires you to keep a reference to the object returned by $.get().
A prehaps easier approach would be to increment a global counter when making a request, and decrement it when a request completes. In your success handler, only show the results if the counter === 0 (e.g. theres no requests pending).
Is there any other way I can go about solving this problem?
Rather than aborting the requests, it might be better to construct the callback function inside $.get in a way that clears the data and displays the new data as a single operation - i.e., doesn't clear the data until the new data is ready.
Javascript only processes a single event/thread at a time, so each AJAX response will be processed serially as they arrive.
In traditional javascript AJAX, we know if readystate is:
0 - The request is not initialized
1- The request has been set up
2 - The request has been sent
3 - The request is in process
4 - The request is complete.
When it comes to jQuery AJAX, we have:
complete property where we code what should happen after completion
success property where we code what should happen if the ajax request succeeds and
error property where we code what should happen if ajax request fails.
All of the above properties lets us code to do something after completion of ajax request. Where can I specify some code to execute something during processing(when readyState is 3) in Jquery Ajax??
As my AJAX script takes too long time to execute, which means, I will not attain 'complete' stage quickly. This seems like nothing is happening to the user. I wanted to initiate another ajax script at processing stage which gets information from server meanwhile and shows the user what has been done so far. Is it possible at all in Javascript? I know there is no multi-threading in Javascript.
I think I made my self clear. But, Please let me know if anything is not making any sense.
I handle this by initiating the first long running request, returning to the user immediately and allowing the process to fork server side for the extended processing.
The initial return ajax call to the user sets them up to 'watch' that process via a flag against the object ( I store them against the object in the database, but you could for instance watch file sizes or other stuff )
Subsequent ajax calls occur in a loop, each one returning setTimeout for the next call, and report on changes to that flag so the progress of the long running process is then visible. Completion of the long running process prompts NOT sending another setTimeout() and showing the overall results.
If your process is not that intensive, a simple spinner would probably do the job and no work for your server process. I usually handle that having $.ajax flip the visibility of a 'spinner' icon that's preloaded on my pages in the same spot for all.
According to jQuery's Ajax documention, they do not expose the readystate change event:
No onreadystatechange mechanism is provided, however, since success,
error, complete and statusCode cover all conceivable requirements.
It would be possible to show a loading image after the initial Ajax request is kicked off (and before getting any "complete" or "success" events, and then start polling a different URL via ajax which will give you the status of the first request, assuming your server can show progress of the long process before it completes.
I have 3 buttons on page.
Each one makes AJAX request by clicking on it.
These all requests should makes in async mode.
But clicking on any button in second time should:
1. Stop current request which was made clicking on this button at first time.
OR
Do Nothing.
Option#1 is prefer.
I know about abort(), but my question - how to detect that Ajax request (from certain button) is still not finished ? Here the main point is - request from certain button. I do not want stop all ajax requests. I want stop only request which was made by clicking in the same button at first time.
In my project i'm using jQuery
is this http://api.jquery.com/category/deferred-object/ can help me ? if yes can you provide any suitable example ?
Thanks
I don't believe deferred objects will do what you want. They're designed more for doing promises and aggregate callbacks. You can look into the state of an ajax call by keeping a reference to the jqXHR object returned by $.ajax though.
var ajax;
function onClick() {
if (!ajax || ajax.state() === "resolved") {
ajax = $.ajax(url);
}
}
you need to have a variable associated with each possible ajax process, which tracks whether that process is currently running. When an ajax call starts, set that variable to indicate it's running. When that ajax call completes, set the variable to indicate that the process has stopped. Then, when the user clicks the button, you can examine the variable to decide whether you need to abort() the ajax call or not.
This question already has answers here:
JavaScript, browsers, window close - send an AJAX request or run a script on window closing
(9 answers)
Closed 6 years ago.
I would like the browser to keep the page open until the ajax requests are sent. This is what I imagine it would look like
var requestsPending = 0;
window.onbeforeunload = function() {
showPleaseWaitMessage();
while(requestsPending > 0);
}
// called before making ajax request, atomic somehow
function ajaxStarted() {
requestsPending++;
}
// called when ajax finishes, also atomic
function ajaxFinished() {
requestsPending--;
}
Unfortunately, JS doesn't do multi-threading. To my understanding, the callback (ajaxFinished) would never be executed because the browser would try to wait until the while loop finishes to execute it, and so the it would loop forever.
What's the right way to do this? Is there maybe a way to force JS to evaluate the next thing in its to-do list and then come back to the while loop? Or some syntax to "join" with an ajax call? I'm using DWR for my ajax.
Thanks,
-Max
Edit Based on your comment below, a revised answer:
If you want to block until a previously-initiated request completes, you can do it like this:
window.onbeforeunload = function(event) {
var s;
event = event || window.event;
if (requestsPending > 0) {
s = "Your most recent changes are still being saved. " +
"If you close the window now, they may not be saved.";
event.returnValue = s;
return s;
}
}
The browser will then prompt the user to ask whether they want to leave the page or stay on it, putting them in control. If they stay on the page and the request has completed while the prompt was up, the next time they go to close the page, it'll let them close it without asking.
Note that on modern browsers, your message will not be shown; instead, the browser will use a generic message. So on modern browsers, returning any non-blank string is sufficient. Still, you may want to return a useful string (such as the above) in case your user is using an obsolete browser that will still show it.
More on asking the user whether to cancel close events here and here.
Old answer :
Ideally, if possible, you want to avoid doing this. :-)
If you can't avoid it, it's possible to make an Ajax request synchronous, so that it blocks the onbeforeunload process until it completes. I don't know DWR, but I expect it has a flag to control whether the request is synchronous or not. In the raw XmlHTTPRequest API, this is the third parameter to open:
req.open('GET', 'http://www.mozilla.org/', false);
^ false = synchronous
Most libraries will have an equivalent. For instance, in Prototype, it's the asynchronous: false flag in the options.
But again, if you can possibly avoid firing off Ajax requests as part of the page unload, I would. There will be a noticeable delay while the request is set up, transmitted, and completed. Much better to have the server use a timeout to close down whatever it is that you're trying to close down with this. (It can be a fairly short timeout; you can keep the session alive by using asynchronous Ajax requests periodically in the page while it's open — say, one a minute, and time out after two minutes.)
In short, you cannot (and shouldn't) do this. If a user closes the browser, it's closing...no unload style events are guaranteed to finish, and something doing AJAX with involves latency is more unlikely to finish.
You should look at firing your events at another point, or change the approach altogether, but making an AJAX call in an unload event is going to unreliable, at best.
As an addendum to the above on the shouldn't part, think about it this way, how many tabs do you usually have open on any given window? I typically have 4-6 chrome windows open with 5-12 tabs each...should my browser window hang open because 1 of those tabs wants to make some AJAX request I don't care about? I wouldn't want it to as a user, so I wouldn't try and do it as a developer. This is just an opinion of course, but food for thought.