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

Ste*_*ins 8 ajax recursion jquery promise

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

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);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

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


更新: 在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);
    });
}
Run Code Online (Sandbox Code Playgroud)

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

Jus*_*ner 5

是.以这种方式进行多个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]);
   }
});
Run Code Online (Sandbox Code Playgroud)


Ben*_*aum 1

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

一些改进可以是:

  • 返回承诺而不是回调参数
  • 使用.mapPush 代替 forEach。
  • 使用.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;
         },{});
    });
}
Run Code Online (Sandbox Code Playgroud)

这可以让你做:

getTemplatesAsync(names).then(function(templates){
     // access templates here
});
Run Code Online (Sandbox Code Playgroud)