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.
Related
I have a unified AJAX request that always does the same thing (fetch data and display it in a table).
I'd like to extend this functionality now. I have a table where I can select table rows and they will become marked.
The problem now is: If I use the pagination to go to a different page and back, the mark on every row is lost.
I'd like to call a function that marks the rows again. How do I call the function after my original AJAX completes - without modifying the original AJAX's onreadystatechange?
Essentially, I'm looking for something like "document.onajaxcompletion"
It doesn't matter if it executes on any non-specific AJAX call either
Pseudo-code:
document.addEventListener("ajaxcompletion", function() { myRowUpdater(); });
Short answer is yes.
The long answer will depend on how you are recording the "mark on every row" with the AJAX request.
If that marking is recorded in a database, then your return to the page should (could) be corrected by the rendering of the HTML getting the data from the database.
If the marking is recorded browser side with localStorage (as an example), then reloading the page should check the localStorage during window.onload and correct the marked items.
These are only two possible solutions. Neither use AJAX to correct the HTML on reload.
It is possible you need to extend the functionality of the AJAX request to record the marking event. That information is missing from your question.
Possible flow:
User loads page
During window.onload, JavaScript creates an onclick event listener
Member clicks item, item state is changed and event listener is called
event listener passes AJAX request to record page and returns a "success" or "fail" response and records the action in a database (or not on a fail)
on "success", the item state is confirmed or changed
on "fail", state is reverted and member is informed of issue
member leaves page
on return to page, database is check and the recorded events are populated.
I went with MutationObserver API to monitor the change to the Table's innerHTML in the end. It works perfectly.
const myObserver = new MutationObserver(myUpdateTableRowMarks);
myObserver.observe(document.getElementById("mytable_tbody"), { childList: true });
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'll be as direct and as specific as possible.
I'm trying to create Greasemonkey addon that would create graph of winnings/loses on: dead link
As you can see, site has front page which dinamicly shows results of wins / loses and how much did which user win/loose. What I'm trying to do is catch every new entry so I can draw some grapsh and or statistics for user / users.
When I access div/span that should have data, it turns out to be empty. I know that reason behind this is that all divs with data relevant to me are empty on load and that they get populated later on.
What I don't know is how to access that data. I can see (using firebug console) that there are GET requests executed all the time and that in those get requests is data that I need.
Can someone tell me or at least point me into right direction, how to access that data every time it gets refreshed / inserted?
You can try using the $.ajaxSuccess function to specify a function in your script to be called everytime an ajax request completes in the main page. This'll be fired for every successful ajax request, whether it pertains to the data you're talking about or not, but should allow you to re-scrape that section of the document to grab any and all data in it after every successful request. You may want to wrap your callback function in a setTimeout of some kind to make sure their own callbacks have a chance to fire and inject/modify the content before you scrape it. It should still seem instantaneous to the user if you set a timeout of, say, 1-10ms.
http://api.jquery.com/ajaxSuccess/
I would like to setup and undo feature that delays my ajax call a set amount of time and gives the user an opportunity to abort the ajax call before it gets called. I would also like to stop the delay and continue with the most recent ajax call if another action is triggered.
For example,
If i sent an email and I'm given 5 min to undo this action, I can send another email to send the previous email and to give this new email 5 min to undo.
I was wondering how I would be able to do this?
You can try to encapsulate the actions and show use the pending actions which use can commit by clicking a button. This way they can any time remove the pending action.
Another way is to create undo action (like if a block of text is deleted, keep the deleted text with position information) that can be executed later to bring system back to previous state.
But if it is something like email sent or data saved to database things get complicated and queuing up pending changes is a better way.
There is an undo/redo module for YUI library which you can explore.
Here is some pseudo-code:
User clicks to send
If there is a previous one saved ...
clear the timeout away
call the send function which will ...
retrieve the saved one
if it hasn't been erased ...
erase the saved one
call ajax to send it
Save the current one away
set the timeout to call the send function (defined above)
Note that "saving" and "retrieving" is simple here. Store it to the 'savedEmail' variable and get it from there. Erasing means you set the 'savedEmail' variable to null.
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.