jQuery not executing in correct order?
I have recently started working with jQuery and today noticed a strange issue with how it's behaving for me. As I understand it, JavaScript is single threaded. So all of it's operations should run in a FIFO basis. However, this did not appear to be the case for me. P开发者_如何学运维lease consider the following.
SETUP is as follows
HTML:
3 divs
div#1 => contains header elements which can be clicked to execute the sort function
div#2 => contains the data that needs to be sorted
div#3 => contains an basic .gif which is used to notify the user that some operation is being performed
jQuery - contains the sort function which does DOM manipulation. Basically, it reads data from the HTML page, stores in a 2D array, and sorts the array. It then clears div#2 (data div) completely and rebuilds it, using data from the sorted array.
EXECUTION was expected to be as follows
- user clicks one of the headers to trigger the sort function
- sort function hides div#2 and shows div#3
- sort function is executed
- once sorting is completed, div#2 (data div) is shown and div#3 is hidden
However, here is what appears to happen
user clicks the headers
sort occurs
hiding and showing of divs happens at the last step
Initially, as I was not able to see any divs being shown/hide, I assumed that it was happening too fast for me to notice. So I added a time delay to the .show() and .hide() functions of jQuery. Once this was done, it was quite apparent that show and hide actions were being done at the very end.
* SOLUTION * After much searching, I managed to get this working as I expected by using jQuery .queue() and .dequeue() functions. The achilles heel here was that I had to insert a 1 millisecond delay between each operation. Then and only then was the browser able to hide/show divs as I wanted. So the operations went something like this:
var theQueue = $({}); // jQuery on an empty object
theQueue.queue("testQueue",
function( next) {
$("#loadingIndicator").show();
$("#cases").hide();
next();
}
);
theQueue.delay( 1, "testQueue" );
theQueue.queue("testQueue",
function( next) {
doSort(columnNumber); //SORT
next();
}
);
theQueue.delay( 1, "testQueue" );
theQueue.queue("testQueue",
function( next) {
$("#loadingIndicator").hide();
$("#cases").show();
next();
}
);
theQueue.dequeue("testQueue");
}
I am certainly not an expert on the matter, but I would think that operations should be executing in the same order as they are called. Is the browser not rendering in the correct order? Is jQuery changing order of operations to make things more efficient?
While the "solution" does the job, I am not convinced that it is the best solution in this scenario. Is there any other way to do this? If needed, I can provide working code examples that will demonstrate the issue. Thank you.
On a different note, I have noticed with large data sets, when user clicks on a header element to trigger sort, browser become unresponsive. I realize it is executing the sort function, but I was hoping there would be a way to avoid this. Any thoughts?
The operations are being executed in the same order that they are called, but the problem is that the DOM elements and what's shown on the screen are two separate things. The process that renders the elements to the screen runs in the same single threaded environment as the Javascript code, so it can't show any changes on the sceen until your script finishes.
To get the changes to show up, you have to end your script, and then resume it once the renderer has had a chance to show the changes.
You can use the setTimeout
method to return control to the browser, and get the rest of the code to start as soon as possible:
$("#loadingIndicator").show();
$("#cases").hide();
window.setTimeout(function(){
doSort(columnNumber); //SORT
$("#loadingIndicator").hide();
$("#cases").show();
}, 0);
.show()
and .hide()
are members of the fx queue, which is executed asynchronously, without halting program execution.
Effects may be queued sequentially by chaining, but other code will execute independently of fx queue execution. The way to get the order of operations the way you want is to create a custom queue like you did, or use the callback functions for each effect.
E.g.
$('#loadingIndicator').show(250,function(){
$('#cases').hide(250,function(){
doSort(columnNumber);
}).show(250, function(){
$('#loadingIndicator').hide(250);})
});
JSFiddle example
ED: I accidentally the whole word.
精彩评论