Упорядочивание ajax запросы

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

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

У кого-либо есть умный шаблон разработки для того, как аккуратно работать через набор, делающий ajax призывы к каждому объекту?

62
задан gnarf 16 June 2010 в 20:14
поделиться

4 ответа

jQuery 1.5+

Я разработал плагин $. AjaxQueue () , который использует $. Deferred , .queue ( ) и $. Ajax () , чтобы также передать обратно обещание , которое выполняется после завершения запроса.

/*
* jQuery.ajaxQueue - A queue for ajax requests
* 
* (c) 2011 Corey Frang
* Dual licensed under the MIT and GPL licenses.
*
* Requires jQuery 1.5+
*/ 
(function($) {

// jQuery on an empty object, we are going to use this as our Queue
var ajaxQueue = $({});

$.ajaxQueue = function( ajaxOpts ) {
    var jqXHR,
        dfd = $.Deferred(),
        promise = dfd.promise();

    // queue our ajax request
    ajaxQueue.queue( doRequest );

    // add the abort method
    promise.abort = function( statusText ) {

        // proxy abort to the jqXHR if it is active
        if ( jqXHR ) {
            return jqXHR.abort( statusText );
        }

        // if there wasn't already a jqXHR we need to remove from queue
        var queue = ajaxQueue.queue(),
            index = $.inArray( doRequest, queue );

        if ( index > -1 ) {
            queue.splice( index, 1 );
        }

        // and then reject the deferred
        dfd.rejectWith( ajaxOpts.context || ajaxOpts,
            [ promise, statusText, "" ] );

        return promise;
    };

    // run the actual query
    function doRequest( next ) {
        jqXHR = $.ajax( ajaxOpts )
            .done( dfd.resolve )
            .fail( dfd.reject )
            .then( next, next );
    }

    return promise;
};

})(jQuery);

jQuery 1.4

Если вы используете jQuery 1.4, вы можете использовать очередь анимации для пустого объекта, чтобы создать свою собственную «очередь» для ваших запросов ajax для элементов.

Вы даже можете учесть это в своей собственной $. Ajax () замене. Этот плагин $. AjaxQueue () использует стандартную очередь fx для jQuery, которая автоматически запускает первый добавленный элемент, если очередь еще не запущена.

(function($) {
  // jQuery on an empty object, we are going to use this as our Queue
  var ajaxQueue = $({});

  $.ajaxQueue = function(ajaxOpts) {
    // hold the original complete function
    var oldComplete = ajaxOpts.complete;

    // queue our ajax request
    ajaxQueue.queue(function(next) {

      // create a complete callback to fire the next event in the queue
      ajaxOpts.complete = function() {
        // fire the original complete if it was there
        if (oldComplete) oldComplete.apply(this, arguments);

        next(); // run the next query in the queue
      };

      // run the query
      $.ajax(ajaxOpts);
    });
  };

})(jQuery);

Пример использования

Итак, у нас есть

    , в котором есть некоторые
  • , которые мы хотим скопировать (используя ajax!) В

      // get each item we want to copy
      $("#items li").each(function(idx) {
      
          // queue up an ajax request
          $.ajaxQueue({
              url: '/echo/html/',
              data: {html : "["+idx+"] "+$(this).html()},
              type: 'POST',
              success: function(data) {
                  // Write to #output
                  $("#output").append($("<li>", { html: data }));
              }
          });
      });
      

      демонстрация jsfiddle - 1.4 версия

111
ответ дан 24 November 2019 в 16:41
поделиться

В идеале сопрограмма с несколькими точками входа, чтобы каждый обратный вызов с сервера мог вызывать одну и ту же сопрограмму, будет аккуратным. Блин, вот-вот это будет реализовано в Javascript 1.7.

Позвольте мне попробовать использовать закрытие ...

function BlockingAjaxCall (URL,arr,AjaxCall,OriginalCallBack)
{    
     var nextindex = function()
     {
         var i =0;
         return function()
         {
             return i++;
         }
     };

     var AjaxCallRecursive = function(){
             var currentindex = nextindex();
             AjaxCall
             (
                 URL,
                 arr[currentindex],
                 function()
                 {
                     OriginalCallBack();
                     if (currentindex < arr.length)
                     {
                         AjaxCallRecursive();
                     }
                 }
             );
     };
     AjaxCallRecursive();    
}
// suppose you always call Ajax like AjaxCall(URL,element,callback) you will do it this way
BlockingAjaxCall(URL,myArray,AjaxCall,CallBack);
3
ответ дан 24 November 2019 в 16:41
поделиться

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

loadSequantially(['/a', '/a/b', 'a/b/c'], function() {alert('all loaded')});

Ниже приведен грубый набросок (рабочий пример, за исключением вызова ajax). Это можно модифицировать, чтобы использовать структуру, подобную очереди, вместо массива

  // load sequentially the given array of URLs and call 'funCallback' when all's done
  function loadSequantially(arrUrls, funCallback) {
     var idx = 0;

     // callback function that is called when individual ajax call is done
     // internally calls next ajax URL in the sequence, or if there aren't any left,
     // calls the final user specified callback function
     var individualLoadCallback = function()   {
        if(++idx >= arrUrls.length) {
           doCallback(arrUrls, funCallback);
        }else {
           loadInternal();
        }
     };

     // makes the ajax call
     var loadInternal = function() {
        if(arrUrls.length > 0)  {
           ajaxCall(arrUrls[idx], individualLoadCallback);
        }else {
           doCallback(arrUrls, funCallback);
        }
     };

     loadInternal();
  };

  // dummy function replace with actual ajax call
  function ajaxCall(url, funCallBack) {
     alert(url)
     funCallBack();
  };

  // final callback when everything's loaded
  function doCallback(arrUrls, func)   {
     try   {
        func();
     }catch(err) {
        // handle errors
     }
  };
3
ответ дан 24 November 2019 в 16:41
поделиться

Я использую http://developer.yahoo.com/yui/3/io/#queue, чтобы получить эту функциональность.

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

1
ответ дан 24 November 2019 в 16:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: