2015-04-24 2 views
1

Мне нужно сделать 3 или менее вызова ajax, и ответы должны быть добавлены к dom в том же порядке, в котором они были запрошены.Ajax звонки внутри цикла нужны последовательные ответы

У меня есть следующая функция, но проблема в том, что ответы, которые я получаю, не обязательно в правильном порядке, когда они присоединяются к dom.

Я бы не хотел использовать свойство async: false, потому что он блокирует пользовательский интерфейс, и это, конечно, удар производительности.

mod.getArticles = function(){ 
    //mod.vars.ajaxCount could start at 0-2 
    for(var i = mod.vars.ajaxCount; i < 3; i++){ 
     //mod.vars.pushIds is an array with the ids to be ajaxed in 
     var id = mod.vars.pushIds[i]; 

     $.ajax({ 
      url: '/ajax/article/' + id + '/', 
      type: "GET", 
      dataType: 'HTML', 
      error: function() { 
       console.error('get article ajax error'); 
      } 
     }).done(function(data) { 
      if (data.length) { 
       mod.appendArticle(data); 
      } else { 
       console.error('get article ajax output error'); 
      } 
     }); 
    } 
}; 
+0

Ответ не в том же порядке запуска, что ajax - это асинхронный и успешный отпечаток до dom, когда скрипт заканчивается, и сервер устанавливает код успеха. Единственный шанс - связать вызовы ajax в скриптах. [Async: false устарел.] – MTS

+0

Франциско, вы можете добавить 'mod.appendArticle()' к вопросу? –

ответ

5

Вы должны добавить статью в определенную позицию, на основе, например, в i переменной у вас есть. Или вы можете дождаться всех запросов и затем добавить их в порядок. Что-то вроде этого:

mod.getArticles = function(){ 
    var load = function(id) { 
     return $.ajax({ 
      url: '/ajax/article/' + id + '/', 
      type: "GET", 
      dataType: 'HTML', 
      error: function() { 
       console.error('get article ajax error'); 
      }); 
     }; 
    var onDone = function(data) { 
      if (data.length) { 
       mod.appendArticle(data); 
      } else { 
       console.error('get article ajax output error'); 
      } 
     }; 
    var requests = []; 
    for(var i = mod.vars.ajaxCount; i < 3; i++){ 
     requests.push(load(mod.vars.pushIds[i])); 
    } 

    $.when.apply(this, requests).done(function() { 
     var results = requests.length > 1 ? arguments : [arguments]; 
     for(var i = 0; i < results.length; i++){ 
      onDone(results[i][0]); 
     } 
    }); 
}; 
+0

Не должны ли дефрагментированные объекты быть частью $ .when? – Pratik

+0

Определенно намного более элегантное решение, чем мое, если я так говорю. –

+0

@Pratik, что вы имеете в виду? Я откладываю отложенные запросы к массиву запросов, а затем применяю этот массив в качестве аргументов в $ .when – ekuusela

1

Вот пример использования i для добавления их в правильном порядке, когда они все догружать:

mod.getArticles = function(){ 
    // initialize an empty array of proper size 
    var articles = Array(3 - mod.vars.ajaxCount); 
    var completed = 0; 
    //mod.vars.ajaxCount could start at 0-2 
    for(var i = mod.vars.ajaxCount; i < 3; i++){ 
     // prevent i from being 3 inside of done callback 
     (function (i){ 
      //mod.vars.pushIds is an array with the ids to be ajaxed in 
      var id = mod.vars.pushIds[i]; 
      $.ajax({ 
       url: '/ajax/article/' + id + '/', 
       type: "GET", 
       dataType: 'HTML', 
       error: function() { 
        console.error('get article ajax error'); 
       } 
      }).done(function(data) { 
       completed++; 
       if (data.length) { 
        // store to array in proper index 
        articles[i - mod.vars.ajaxCount] = data; 
       } else { 
        console.error('get article ajax output error'); 
       } 
       // if all are completed, push in proper order 
       if (completed == 3 - mod.vars.ajaxCount) { 
        // iterate through articles 
        for (var j = mod.vars.ajaxCount; j < 3; j++) { 
         // check if article loaded properly 
         if (articles[j - mod.vars.ajaxCount]) { 
          mod.appendArticle(articles[j - mod.vars.ajaxCount]); 
         } 
        } 
       } 
      }); 
     }(i)); 
    } 
}; 
+0

Я не думаю, что это сработает. Когда вы добираетесь: статьи [i - mod.vars.ajaxCount] 'i' равно 3 каждый раз; цикл for работает до завершения. –

+0

@FranciscoAlvarez Нет, это не так, вот почему я завернул его в анонимную функцию –

+0

благодарю вас за ответ, я не заметил этой детали. Похоже, очень простое решение, я обязательно попробую. –

1
var success1 = $.ajax... 
var success2 = $.ajax... 
var success3 = $.ajax... 
$.when(success1, success2, success3).apply(ans1, ans2, ans3) { 
finalDOM = ans1[0]+ans2[0]+ans3[0]; 
} 

Проверить this для получения дополнительной справки. Это все еще асинхронно, но он ждет их завершения. Вы уже знаете порядок вызова, как это делается через ваш код, поэтому добавьте элементы dom соответственно.

0

Попробуйте использовать элементы в пределах mod.vars массив в качестве индексов; чтобы установить как id property of $.ajaxSettings, set received data at this.id индекс в пределах массива ответов. resultsarray должно быть в том же порядке, что и mod.vars, когда все запросы завершены.

var mod = { 
    "vars": [0, 1, 2] 
}; 

mod.getArticles = function() { 
    var results = []; 
    var ids = this.vars; 
    var request = function request(id) { 
      return $.ajax({ 
       type: "GET", 
       url: "/ajax/article/" + id + "/", 
       // set `id` at `$.ajaxSettings` , 
       // available at returned `jqxhr` object 
       id: id 
      }) 
      .then(function (data, textStatus, jqxhr) { 
       // insert response `data` at `id` index within `results` array 
       console.log(data); // `data` returned unordered 
       // set `data` at `id` index within `results 
       results[this.id] = data; 
       return results[this.id] 
      }, function (jqxhr, textStatus, errorThrown) { 
       console.log("get article ajax error", errorThrown); 
       return jqxhr 
      }); 
    }; 

    return $.when.apply(this, $.map(ids, function (id) { 
     return request(id) 
    })) 
    .then(function() { 
     $.map(arguments, function (value, key) { 
      if (value.length) { 
       // append `value`:`data` returned by `$.ajax()`, 
       // in order set by `mod.vars` items:`id` item at `request` 
       mod.appendArticle(value); 
      } else { 
       console.error("get article ajax output error"); 
      }; 
     }) 
    }); 

}; 

mod.getArticles(); 

jsfiddle http://jsfiddle.net/6j7vempp/2/

0

Решения, которые полагаются исключительно на закрытий будет работать до точки. Они будут последовательно добавлять статьи одного звонка mod.getArticles() в правильном порядке. Но рассмотрите второй звонок до того, как первый будет полностью удовлетворен. Из-за асинхронизма процесса набор статей второго вызова можно было бы добавить до первого.

Лучшим решением будет гарантировать, что даже быстрый последовательность огневого mod.getArticles() вызовов будет:

  • добавлять статьи каждый вызов в правильном порядке
  • Append все наборы статей в правильном порядке

Один из подходов к каждому из них:

  • синхронно добавьте контейнер (div) в DOM и сохраните ссылку на него.
  • асинхронно заполняет контейнер содержимым, когда оно поступит.

Для этого вам необходимо будет изменить mod.appendArticle(), чтобы принять второй параметр - ссылку на элемент контейнера.

mod.appendArticle = function(data, $container) { 
    ... 
}; 

Для удобства, вы можете также выбрать, чтобы создать новый метод, mod.appendArticleContainer(), который создает DIV, присоединяет его к DOM и возвращает ссылку на него.

mod.appendArticleContainer = function() { 
    //put a container somewhere in the DOM, and return a reference to it. 
    return $("<div/>").appendTo("wherever"); 
}; 

Теперь mod.getArticles() все еще очень просто:

mod.getArticles = function() { 
    //Here, .slice() returns a new array containing the required portion of `mod.vars.pushIds`. 
    //This allows `$.map()` to be used instead of a more cumbersome `for` loop. 
    var promises = $.map(mod.vars.pushIds.slice(mod.vars.ajaxCount, 3), function(id) { 
     var $container = mod.appendArticleContainer();//<<< synchronous creation of a container 
     return $.ajax({ 
      url: '/ajax/article/' + id + '/', 
      type: "GET", 
      dataType: 'HTML' 
     }).then(function(data) { 
      if (data.length) { 
       mod.appendArticle(data, $container);//<<< asynchronous insertion of content 
      } else { 
       return $.Deferred().reject(new Error("get article ajax output error")); 
      } 
     }).then(null, function(e) { 
      $container.remove();//container will never be filled, so can be removed. 
      console.error(e); 
      return $.when(); // mark promise as "handled" 
     }); 
    }); 
    return $.when.apply(null, promises); 
}; 

mod.getArticles() теперь возвращает обещание завершения его абонента, что позволяет в дальнейшем сцепление при необходимости.

0

Вместо использования цикла for. Вызовите свою функцию в ответной части предыдущей функции.

//create a global variable 
     var counter = 0; 

     function yourFunc(){ 

     mod.getArticles = function(){ 
      //mod.vars.ajaxCount could start at 0-2 
      //mod.vars.pushIds is an array with the ids to be ajaxed in 
       var id = mod.vars.pushIds[counter ]; 

       $.ajax({ 
        url: '/ajax/article/' + id + '/', 
        type: "GET", 
        dataType: 'HTML', 
        error: function() { 
         console.error('get article ajax error'); 
        } 
       }).done(function(data) { 
        if (data.length) { 
         mod.appendArticle(data); 
        } else { 
         console.error('get article ajax output error'); 
        } 
     //increment & check your loop condition here, so that your responses will be appended in same order 
     counter++; 
     if (counter < 3) 
       { yourFunc(); } 
       }); 

     }; 
     } 
+0

Я реализовал это решение, но проблема в том, что вызовы становятся синхронными, препятствуя производительности. Спасибо за сообщение. –

Смежные вопросы