5

我希望在 JavaScript/jQuery 中对任意数量的可能可选函数调用进行排队。例如,在运行第二个(或第三个、第四个等)函数或 AJAX 调用之前,我可能需要确保用户已通过身份验证并设置了 cookie。

我考虑使用最近添加的 jQuery.Deferred 来执行此操作,但发现调用的触发顺序无关紧要(真正的异步样式)。另外,我读到一旦解决了 Deferred 实例,就不可能取消解决它。

这就是我目前所处的位置。最初,我正在考虑将 Deferred 实例设置为已解析,然后在堆栈中出现可选函数时取消解析它。

var d = $.Deferred(),
    chained = d,
    d.resolve(),
    div = extra.find( "div:first" );

if ( extra.attr( "requires-auth" ) != undefined && !config.user_is_authenticated )
  chained = chained.pipe( authenticate );

if ( div.length )
  chained = chained.pipe( prepareExtra( div ) );

// When the two optional methods are resolved, show the content
chained.done( function() {
  extra.fadeIn( 500 )
} );

我的问题是,在纯 JavaScript/jQuery 中排队(0 到 N)AJAX 调用的最佳方式是什么?(不使用插件)。

达!

编辑 2:已解决! 这是一些工作示例,一个不带 AJAX,一个带: https ://gist.github.com/1021429 https://gist.github.com/1021435

4

4 回答 4

7

尝试将您的初始 Deferred 解决为最后一件事:

var d = $.Deferred(),
    chained = d;

// optionally chain callbacks with chained = chained.pipe
if (condition) {
    chained = chained.pipe(function () {
        return $.ajax({...}); // Must return a new Promise
    });
}

chained.done(function () {
    // all chains should be processed now
});

d.resolve(); // finally, resolve the initial Deferred
于 2011-06-09T15:12:22.657 回答
0

使用序列助手:

https://github.com/michiel/asynchelper-js/blob/master/lib/sequencer.js

我有一个类似的问题:jQuery Ajax / .each 回调,在 ajax 完成之前下一个“每个”触发

于 2011-06-09T15:50:40.943 回答
0

我过去通过 ajax 调用返回其他脚本来处理这个问题。对我来说,这是最好的解决方案。

但是,您想要一个纯 js 方法,所以我会试一试。

var ScriptQueue = {
    scripts: [],
    readyToProcess: false,
    timer: null,
    stopTimer: function() {
        clearTimeout(ScriptQueue.timer);
        ScriptQueue.timer = null;
    },
    queue: function(functionToQueue) {
        ScriptQueue.stopTimer();
        ScriptQueue.scripts.push(functionToQueue);
        ScriptQueue.processNext();
    }, 
    processNext: function() {
       if (!readyToProcess || ScriptQueue.scripts.length == 0) {
           ScriptQueue.timer = setTimeout(ScriptQueue.processNext, 30000); // try again in 30 sec
       } else {
           ScriptQueue.stopTimer();
           var _function = ScriptQueue.scripts.shift();
           _function.call();
           ScriptQueue.processNext();
       }
    }
}

$(function(){

    // queue some stuff

    $('a').each(function() {
        ScriptQueue.queue(function() {
            console.info("running some link action");
        } );
    });

    // authorization
    $.ajax({
        url: yourURL
        success: function(data) {
           if (data == "correct response") {
               ScriptQueue.readyToProcess = true;
               ScriptQueue.processNext();
           }
        }
    })


});

我不知道这是否可行(未经测试),但我想提出一个可能的替代Deferred解决方案(看起来很有希望)。也许它会导致进一步的讨论,也许会被忽略。

于 2011-06-09T15:53:02.557 回答
0

未经测试,但jQuery.when应该可以很好地解决这个问题:

var q = [];
function queue(promise, callback) {
    var ready = $.when.apply($, q); // resolves when all current elements 
                                   // of the queue have resolved
    q.push(promise);
    ready.done(function() {
        q.shift();
        var arg = Array.prototype.pop.call(arguments);
        callback.call(promise, arg);
    });
}
于 2011-06-09T17:27:27.417 回答