2014-09-28 2 views
1

Я уже прошел этот вопрос. Are recursive AJAX calls a bad idea? Здесь ответ, представленный Джастином Нисснером, хорош (с использованием обещаний). Но моя проблема немного отличается. Я хочу позвонить 10 ajax calls рекурсивно. Как после завершения первого вызова Ajax, я сделать что данные (предоставляемые Ajax вызова), на мой взгляд, и в то же время я буду называть вторым Аякса call.So мой пример кода будет выглядеть следующим образом:Создание множества вызовов AJAX рекурсивно - плохая идея

(function() { 
    var downloadAsync = function(url, callback) { 
     var httpRequest; 
     if (window.XMLHttpRequest) { 
      httpRequest = new XMLHttpRequest(); 
     } else if (window.ActiveXObject) { 
      httpRequest = new ActiveXObject("Microsoft.XMLHTTP"); 
     } 
     httpRequest.onreadystatechange = function() { 
      if (httpRequest.readyState === 4 && httpRequest.status === 200) { 
       callback(httpRequest.responseText); 
      } 
     } 
     httpRequest.open("GET", url, true); 
     httpRequest.send(); 
    } 

    function renderData(data) { 
     //data render logic   
    } 
    downloadAsync("mathmatics.json", function(response) { 
     renderData(response); 
     downloadAsync("science.json", function(response) { 
      renderData(response) 
      downloadAsync("english.json", function(response) { 
       renderData(response); 
       .................................... 
      }); 
     }); 
    }); 

})(); 

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

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

  1. Примечание: рендеринг данных по успеху ajax - мой приоритет.
  2. Редактировать - Поддержка браузера - луч хрома, firefox и IE-11.
  3. Edit - по улучшению комментариев:
var array = ["mathematics.json", "science.json", "english.json"]; 
for (var i = 0; i < array.length; i++) { 
    downloadAsync(array[i], renderData); 
} 

function renderData(data) { 
    console.log(data); 
    } 
+1

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

+0

Если вы просто держите порядок в том, какие данные идут туда, вы можете просто вызвать все функции ajax в простом цикле, и браузер будет стоять в очереди но они, конечно, не закончатся по порядку, вам придется оставить этот заказ самостоятельно, но это легко, даже без обещаний, просто передать индекс функции «renderData», чтобы узнать, какой запрос закончен и т. д. – adeneo

+0

@charlietfl извините, моя ошибка, отредактировал вопрос. – Anshul

ответ

2

Уплотненный Ajax вызывает работу. Есть некоторые недостатки, хотя:

  • Если вы делаете обработку реальной ошибки, он может получить довольно грязный с несколькими вызовами вложенной АЯКС и часто в конечном итоге повторять обработку ошибок на каждом уровне вложенности.
  • По мнению некоторых людей, глубокое вложение может привести к менее читаемому коду, чем другие методы.
  • Если какой-либо код в вложенности может генерировать исключения, вам нужно много обработчиков исключений, чтобы правильно улавливать все исключения и его трудно распространять ошибки - потому что это асинхронные обратные вызовы, вы не можете просто перехватывать исключения в одном месте.

См Правки в конце Ответ Теперь о том, что смысл вопроса был осветленный

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

Вы не говорите, что обещание библиотеки вы планируете использовать (есть несколько), но вот один сделано с помощью Bluebird (хотя код будет подобен или идентичен с другими библиотеками):

(function() { 
    // downloadAsync now returns a promise rather than uses a callback 
    function downloadAsync(url) { 
     return new Promise(function(resolve, reject) { 
      var httpRequest = new XMLHttpRequest(); 
      httpRequest.onreadystatechange = function() { 
       if (httpRequest.readyState === 4) { 
        if (httpRequest.status === 200) { 
         resolve(httpRequest.responseText); 
        } else { 
         reject(httpRequest.status); 
        } 
       } 
      } 
      httpRequest.open("GET", url, true); 
      httpRequest.send(); 
     } 
    } 

    function renderData(data) { 
     //data render logic   
    } 
    var items = ["mathmatics.json", "science.json", "english.json"]; 
    var promises = items.map(function(path) { 
     return downloadAsync(path); 
    }); 

    // Promise.all collects all the promise results and 
    // calls .then only when all the promises have completed 
    Promise.all(promises).then(function(data) { 
     data.forEach(renderData) 
    }).catch(function(e) { 
     // handle errors here 
    }); 

})(); 

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


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

// note we are passing an index here so you know which column it is in case that isn't 
// already specified in the data 
function renderData(index, data) { 
    //data render logic   
} 

// are you sure you want a leading/on only one of these three? 
var items = ["mathmatics.json", "science.json", "english.json"]; 
items.forEach(function(value, index) { 
    downloadAsync(value).then(function(data) { 
     renderData(index, data); 
    }); 
}); 

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


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

downloadAsync("mathmatics.json", renderData); 
downloadAsync("science.json", renderData); 
downloadAsync("english.json", renderData); 

Это запустит все три параллельно и делают каждый из них сразу по мере поступления данных.


Или, если у вас было больше, чем три, и вы поставить имена файлов в массив любой длины, и вы можете сделать это:

["mathmatics.json", "science.json", "english.json"].forEach(function(item) { 
    downloadAsync(item, renderData); 
}); 
+0

@pandit - Примечание: в зависимости от того, какие версии браузера вы используете, вам может потребоваться использовать библиотеку Promise, такую ​​как Bluebird или Q, чтобы гарантировать поддержку обещаний. – jfriend00

+0

У меня есть 10 столбцов, и я показываю данные каждого вызова ajax в столбцах, моя идея - показать данные как можно скорее. Вот почему я так делаю. В вашем подходе я могу отображать целые данные только тогда, когда завершен весь вызов ajax. – Anshul

+0

@pandit - я так программирую, потому что так работал ваш исходный код (он делал по одному), и я предполагал, что вы так хотели. Это не должно быть так, если требования или желание разные. Я могу добавить такой пример к моему ответу. – jfriend00

0

Поскольку вы делаете новые браузеры - ваша жизнь может быть лот проще с обещаниями.

Вы проверяете вещи, не имеющие значения с IE6, вы можете значительно упростить свою работу.

Вот как:

function downloadAsync(url){ 
    return new Promise(function(fulfill, reject){ 
     var xhr = new XMLHttpRequest; 
     xhr.open("GET", url); 
     xhr.onload = function(){ resolve(xhr.responseText); }); 
     xhr.onerror = reject; 
     xhr.send(); 
    }); 
} 

Нет необходимости для проверки на XMLHttpRequest, нет потребности в проверках состояния, простой OnLoad - обратите внимание, что мы также добавили OnError поэтому мы не молчанию ошибок.

Теперь давайте загрузим все три сразу:

// your pages 
var pages = ["mathmatics.json", "science.json", "english.json"] 
// your downloads and renders 
var promises = pages.map(downloadAsync). 
        /*map(JSON.parse).*/ 
        map(renderData); 
Promise.all(promises).then(function(){ 
    // code here runs when it's all done. 
}); 
Смежные вопросы