27

I've seen a number of posts (append supposedly immediate) with conflicting accepted answers on this. We're using JQuery 1.4 (http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js) and append() seems to be asynchronous, such that:

Edited to show code in context of AJAX callback

 ...
 var message = $.ajax({
   type: "GET",
   url: "/getVolumes/" +  _Id,
   async: false 
 }).responseText;
 if (parseInt(message) != 0){
   var $results = $(message);
   $MAIN_DIV.append($results);
   retrieveTargets();
 }
...    
function retrieveTargets(){
  var $targets = $(".resultTargets");
}

Executes and creates the page as expected, yet the targets query yields nothing at runtime. Running the same code in the JS console retrieves the elements as expected.

If this is the expected behavior in JQuery what's the proper way to wait until append is finished?

Community
  • 1
  • 1
RSG
  • 7,013
  • 6
  • 36
  • 51
  • 2
    jQuery 1.8?? how come?? You're from the future?? :) – DrStrangeLove Feb 22 '11 at 23:21
  • 2
    Append is synchronous but your Ajax call isn't. Where is this code located? In the callback function of your ajax call? – Capsule Feb 22 '11 at 23:23
  • Edited with the right version. I bet this would work the way I want in 1.8. – RSG Feb 22 '11 at 23:25
  • 1
    what is .resultTargets? is it an element in your ajax response? You could access it that way too: var targets = $results.find('.resultTargets'); – Andy Feb 22 '11 at 23:30
  • What happens if you place `console.log( $MAIN_DIV.length )` just before the `$MAIN_DIV.append(...`? – user113716 Feb 22 '11 at 23:37

2 Answers2

28

All of the comments helped track this down. I was following a red herring in the console. The problem wasn't with synchronicity, it was with the next lines:

$targets.each( function(){
  ...
  this.html();
  ...

Needed to be

$(this).html();

In short, everyone was correct. Jquery append() behaves synchronously.

RSG
  • 7,013
  • 6
  • 36
  • 51
  • But beware of DOM nuisances like [this](https://stackoverflow.com/questions/6068955/jquery-function-after-append#comment7028508_6069060) which can still lead to unexpected results (along the same lines as `async` functions do) – y2k-shubham Oct 01 '20 at 15:27
12

Try this, if things don't work after an append.

$('#dynamic-container').append(<your-content>) ;
setTimeout(function() {
    ...code which addresses elements inside #dynamic-container...
},0) ;

More Details:

  • Apparently append is synchronous
  • Apparently the DOM doesn't update synchronously, especially in Google Chrome, I faced this problem when trying to retrieve the height of a div after an append
  • My assumption was that there were browser update threads that updated asynchronously, more comments on that below, still not clear on how things work, but the solution works in all cases for me.
pragman
  • 1,564
  • 16
  • 19
  • 1
    This is incorrect. The browser will update its layout, even if it does not visibly render to the user, when JavaScript request data or measurements from the DOM. (This is the cause of [layout thrashing](http://wilsonpage.co.uk/preventing-layout-thrashing/).) – Alan H. Dec 08 '14 at 20:43
  • Ok, the render threads part is my assumption about how the browser handles UI updates. I faced this issue in my code, and fixed it using the solution above. It could even be that the layouting code runs after the function completes in the same thread. I'm no expert on how the browser works – pragman Dec 12 '14 at 15:18
  • 1
    I hate to say this, but I think you are mistaken. I doubt you would be able to produce a simple reproduction of the issue above (some jsfiddle), isolating the problem; `.append` is indeed entirely synchronous. Also please note that JavaScript is single-threaded and no to things (including the browser) are mutating data at the same time. – Alan H. Dec 12 '14 at 19:03
  • ok, this doesn't make sense to me then: i checked my code, and I'm appending an agility.js object to the DOM tree. Agility fires an event which then calls jQuery's apprend to add the view of the object to the DOM tree. Whats puzzling me is, if javascript single-threaded, then the event triggering should result in the agility.js handler being called immediately, which doesn't seem to be happening. Thats why I ended up using the setTimeout. BTW, I don't see any setTimeout calls in agility.js – pragman Dec 13 '14 at 09:18
  • Ah, you should read up on [the event loop](https://www.google.com/webhp?q=javascript+event+loop) :) – Alan H. Dec 15 '14 at 22:33
  • 2
    Ah! so its the event and not the thread thats delaying the render. Thanks for that Alan. – pragman Jan 04 '15 at 03:36
  • Ah so, the event loop was deferring the execution of the AJAX append...awesomeness, updated my reply to help other folks who might have landed on the same confusion – pragman Jan 04 '15 at 03:43
  • @AlanH. If append() is entirely synchronous, how would you explain the problem stated in this question: http://stackoverflow.com/questions/6068955/jquery-function-after-append? Thanks! – Jan Żankowski Feb 18 '15 at 11:35
  • @JanZankowski The person posting that question also misunderstands the situation. But they did not post any code or jsfiddle showing the error, so who knows what they want. They don’t seem to have heard of "layout thrashing" or they would understand why their assumptions are in fact impossible – Alan H. Mar 25 '15 at 04:03