2012-05-21 3 views
2

У меня есть массив URL-адресов для загрузки асинхронно, например.jQuery: добавить асинхронно загруженное содержимое, поддерживая порядок

var toLoad = ['snippet1.html', 'snippet2.html', ... ]; 

Я пытаюсь загрузить каждый фрагмент кода с помощью AJAX и добавить его к родителю <div>, сохраняя порядок содержания в массиве. Из-за того, как настроен остальная часть моего кода (и по соображениям производительности), I не хотите загрузить синхронно, либо с async:false, либо путем цепочки вызовов .ajax(), как предложено в ответах на this similar question. Вместо этого я хотел бы поместить логику в функцию обратного вызова AJAX, чтобы правильно загрузить загруженные фрагменты, основываясь на индексе.

Следующий код работает:

var $parent = $('#mydiv'); 
toLoad.forEach(function(url, i) { 
    // load snippet 
    $.get(url, function(snippet) { 
     // attach order to DOM element 
     snippet = $(snippet).data('order', i); 
     // find the sibling with the next lowest order number 
     var $prev = $parent 
      .children() 
      .filter(function() { 
       return $(this).data('order') < i 
      }) 
      .last(); 
     if ($prev[0]) snippet.insertAfter($prev); 
     else $parent.prepend(snippet); 
    }); 
}); 

... но я не люблю его. В частности, мне не нравится прикреплять заказ к элементу DOM с помощью .data(); это кажется уродливым, и я бы предпочел не вставлять это в DOM, если я могу ему помочь.

Есть ли лучший способ достичь цели асинхронной загрузки содержимого в div с предопределенным порядком?

+1

было бы приемлемо, чтобы отложить всю нагрузку до тех пор, после того, как все значения были извлечены? Затем вы можете построить массив, отслеживающий результаты каждого запроса, и добавьте его в DOM только после того, как будут получены все URL-адреса. – DCoder

+0

@DCoder - Это может сработать - но это не идеально, потому что мне пришлось бы добавить дополнительную логику для отслеживания завершения всех вызовов. – nrabinowitz

ответ

2

Если ваша основная проблема использует .data(), вы можете сохранить свой собственный массив, который связывает элементы узла узла с значениями.

var map = [ 
    {order: 5, nodeReference: ...}, 
    {order: 9, nodeReference: ...}, 
    {order: 1, nodeReference: ...} 
]; 
function data(node) { 
    // loop through map, comparing to nodeReference to get the order 
} 

// а затем ...

.filter(function() { 
     return data(this) < i 
    }) 

ваш код в основном остается тем же, за исключением того, что вам нужно добавить к карте, когда вы добавляете что-то к йот.

Я старался бы продолжать постепенно добавлять вещи в дом, как только они загружаются, как и сейчас. Я не стал бы ждать, пока все будет загружено, или даже добавит их в порядок. пусть заказ будет работать в конце концов, как и вы сейчас. это то, как веб-браузеры загружают изображения на веб-страницах, и есть серьезные причины для этого.

+0

Это хорошее предложение; вы можете сделать это еще проще, просто сделав 'map' массив элементов DOM, вставив в определенные индексы и проверив для' map.indexOf (this) 'вместо того, чтобы перебирать. – nrabinowitz

+0

ya, это мог сработать. Было бы даже лучше, если бы вы могли индексировать объект, например, «map [node] = order;», но свойства javascript должны быть скалярными, и, насколько мне известно, DOMNode не предлагает подходящий уникальный идентификатор, например хеш-код или серийный идентификатор, который можно использовать. – goat

3

Там просто рекурсии, не дожидаясь, пока одна закончена до начала следующего один:

var toLoad = ['snippet1.html', 'snippet2.html', ....]; 
var $parent = $('#mydiv'); 
var i = 0; 

getSnippet(toLoad[i]); 

function getSnippet(url) { 
    $.get(url, function(snippet) { 
     $parent.append(snippet); 
     if (i<toLoad.length) getSnippet(toLoad[i++]); 
    }); 
}​ 

то делает их все сразу, просто приклеить их в массив, выполнив done() функции одну за другой, чтобы сделать уверены, что элементы вставляются в порядке:

var toLoad = ['snippet1.html', 'snippet2.html', 'snippet3.html']; 
var $parent = $('#mydiv'); 
var gets = []; 

toLoad.forEach(function(url, i) { 
    var XHR = $.get(url); 
    gets.push(XHR); 
}); 

gets[0].done(function(snippet) { 
    $parent.append(snippet); 
    gets[1].done(function(snippet) { 
     $parent.append(snippet); 
     gets[2].done(function(snippet) { 
      $parent.append(snippet); 
     }); 
    }); 
}); 
​ 

, который, вероятно, можно было бы сделать в каком-то цикле, если делать много вызовов AJAX.

Тогда есть deffered objects и promises:

$.when($.get(toLoad[0]), 
     $.get(toLoad[1]) 
     $.get(toLoad[2]) 
    ).done(function(value1, value2, value3) { 
     // value1 etc. are arguments resolved for the ajax requests, respectively 
     // arguments are [ "success", statusText, jqXHR ] 
     $parent.append(value1[2]+value2[2]+value3[2]); 
     } 
}); 
Смежные вопросы