递归AJAX调用是个坏主意吗?

我有一个简单的函数来提取模板数组:

function getTemplates(names, done, templates, index) { if (!index) index = 0; if (!templates) templates = {}; if (index === names.length) return done(templates); $.ajax({ url: '/templates/' + names[index] + '.min.html', success: function (data, status, xhr) { templates[names[index++]] = data; return getTemplates(names, done, templates, index); } }); } 

从一个到另一个,直到它们全部被检索,然后回调到调用函数,我似乎合乎逻辑。 但我很好奇,如果这样做有任何不良副作用。 到目前为止我还没有看到任何东西,但是我不想在没有首先了解任何潜在问题的情况下进行生产。


更新:在Google和BenjaminGruenbaum的帮助下,我设计了一个解决方案:

 function getTemplatesAsync(names, done) { var calls = []; var templates = {}; names.forEach(function (name, index) { calls.push( $.ajax({ url: '/templates/' + names[index] + '.min.html', success: function (data, status, xhr) { templates[names[index++]] = data; } }) ); }); $.when.apply($, calls).done(function () { // using "templates" here feels fragile for some reason. Am I wrong? return done(templates); }); } 

我在这里使用templates因为我需要能够按名称引用每个模板,但不知何故它感觉很脆弱或不可靠。 这看起来像一个安全的事情吗?

您的更新代码比最初的代码要好得多,但它仍有一些问题,主要是混合承诺和回调,而不是使用语言function(返回值)而不使用映射。

一些改进可以是:

  • 返回promise而不是回调参数
  • 使用.map而不是forEach with push。
  • 使用.then而不是成功回调来避免两个处理程序同样的事情和可能未指定的行为(何时首先执行?是否success: ?)

我们可以这样做:

 function getTemplatesAsync(names) { return $.when.apply(null,names.map(function (name, index) { return $.get('/templates/' + names[index] + '.min.html'); }).then(function(results){ // map arguments to names return Array.prototype.reduce.call(arguments, function(obj,cur,idx){ obj[names[idx]] = cur; return obj; },{}); }); } 

这可以让你做到:

 getTemplatesAsync(names).then(function(templates){ // access templates here }); 

是。 以这种方式进行多个AJAX调用是一个坏主意,但可能不是你想的原因。

这将导致所有调用按顺序执行,而不是并行调用并等待它们以这种方式完成。

使用promises进行所有通话,然后在继续之前等待所有通话完成后,你会好得多。 它看起来像:

 var promises = [], templates = [], i; for(i = 0; i < names.length; i++) { promises.push($.get('/templates/' + names[i] + '.min.html')); } $.when.apply($, promises).done(function(responses) { for(i = 0; i < responses.length; i++) { templates.push(responses[i][0]); } }); 

虽然它看起来是递归的(我也使用术语递归Ajax )技术上你的函数在再次被调用之前退出,所以实际上并不是递归…也许我们应该把它们称为“链式”Ajax调用,因为它只是链接异步一起活动? 🙂

如果您不介意一次排队Ajax请求,那么这样做是没有问题的。 我用这种方式几次以确保带宽使用是可以接受的。

您需要注意边缘情况,以便它正常处理服务器错误。

这实际上是处理移动设备的一种很好的技术,这种设备会立即阻止大量请求。

我写了一个插件,通过Ajax加载了一个庞大的应用程序表单的部分,发现像iPad这样的设备无法应对多个同时发生的Ajax请求。 我最后使用递归/链式Ajax调用来解决问题(并且还获得了不会使我们的服务器窒息的奖励):)