我如何推迟这个javascript电话?

时间:2011-08-24 19:19:48

标签: javascript jquery

我正在试图弄清楚如何完成这个工作流程,但似乎无法确定它。我在页面上有 n <select>个元素。加载页面时,对于每个<select>元素,我需要进行$.get(...);调用。一旦所有这些调用完成,那么,只有这样我才需要运行一个额外的功能。以下是一些示例代码,可以更好地解释:

function doWork(selectEl) {
    var getData = ...; // build request data based on selectEl

    $.get('/foo/bar', getData, function (data) {
        // Do something to selectEl with the result
    });
}

function doMoreWork() {
    // Do something with all the selects now that they are ready
}

$(function () {
    // For each of the select elements on the page
    $('select').each(function(index, selectEl) {
        // Go do some AJAX-fetching of additional data
        doWork(selectEl);
    });

    // Once *all* the $.get(...) calls are done, do more things
    doMoreWork();
});

使用上面的代码,doMoreWork()通常在所有异步$.get(...);调用都有机会返回之前调用;这不是我想要的。在$.get(...);被调用之前,我需要完成{{1>}次调用的所有。基本上,我需要在上面例子中的所有doMoreWork()调用完成后执行各种回调。

我将如何完成这项工作?

7 个答案:

答案 0 :(得分:5)

  1. 每次拨打doWork时,都会递增一个计数器。

  2. 每次回复时,都会递减计数器。

  3. 当计数器到达doMoreWork时,让回调调用0

  4. var counter = 0;
    
    function doWork(selectEl) {
        counter++;
        var getData = ...; // build request data based on selectEl
    
        $.get('/foo/bar', getData, function (data) {
            counter--;
            if( !counter ) { doMoreWork(); }
        });
    }
    
    function doMoreWork() {
        // Do something with all the selects now that they are ready
    }
    
    $(function () {
        // For each of the select elements on the page
        $('select').each(function(index, selectEl) {
            // Go do some AJAX-fetching of additional data
            doWork(selectEl);
        });
    });
    

答案 1 :(得分:4)

我会写一个类似的东西:

function synchronizer(query, action, cleanup) {
    this.query = query;
    this.action = action;
    this.cleanup = cleanup;
    this.remaining = query.length;
    this.complete = function() {
        this.remaining -= 1;
        if (this.remaining == 0) { this.cleanup(query); }
    }
    this.run = function() {
        query.each(function(index, which) { action(which, this.complete); })
    }
}

// Aargh. Expecting doWork() to call a passed-in continuation seems ugly to me
// as opposed to somehow wrapping doWork within the synchronizer... but I can't
// think of a way to make that work.

function doWork(element, next) {
    var getData = ...; // build request data based on element

    $.get('/foo/bar', getData, function(data) {
        // Do something to element with the result, and then
        next();
    });
}

function doMoreWork(elements) {
    // Do something with all the selects now that they are ready
}

new synchronizer($('select'), doWork, doMoreWork).run();

答案 2 :(得分:3)

跟踪尚未完成的Ajax调用次数,并在没有剩余的时间内执行doMoreWork()

$(function(){
    var workLeft = $('select').length;

    function doWork(selectEl) {
        var getData = ...; // build request data based on selectEl

        $.get('/foo/bar', getData, function (data) {
            // Do something to selectEl with the result

            // If done all work
            if(!(--workLeft)){
                doMoreWork();
            }                
        });
    }

    function doMoreWork() {
        // Do something with all the selects now that they are ready
    }

    // For each of the select elements on the page
    $('select').each(function(index, selectEl) {
        // Go do some AJAX-fetching of additional data
        doWork(selectEl);
    });
});

您可能还想捕获ajax错误。

答案 3 :(得分:2)

您可以使用jQuery的$.when将多个Deferred对象连接到一个:

$.when.apply($, $('select').map(function(index, selectEl) {
    return $.ajax(....);
}).get()).done(function() {
    // All AJAX calls finished
});

基本上,$.when将多个Deferred对象作为每个参数,并将它们作为一个包装在一起通过跟踪已完成的子延迟的数量来延迟,类似于这里的几个答案如何手动实现它。 / p>

以上代码的更易读的版本是:

var requests = [];
$('select').each(function(index, selectEl) {
    request.push($.ajax(....));
}
$.when.apply($, requests).done(function() {
    // All AJAX calls finished
});

答案 4 :(得分:2)

也许你可以使用JavaScript underscore library's after function

(注意:我没有测试过这段代码)

var numberOfSelectElements = n;
var finished = _after(numberOfSelectElements, doMoreWork);

function doWork(selectEl) {
    var getData = ...; // build request data based on selectEl

    $.get('/foo/bar', getData, function (data) {
        finished();
    });
}

function doMoreWork() {
    // Do something with all the selects now that they are ready
}

$(function () {
    // For each of the select elements on the page
    $('select').each(function(index, selectEl) {
        // Go do some AJAX-fetching of additional data
        doWork(selectEl);
    });
});

答案 5 :(得分:1)

使用延期:

function doWork(selectEl) {
    var getData = ...;

    // return Deferred object
    return $.get('/foo/bar', getData, function (data) {

    });
}


var selects = $('select');

function doItem(i) {
    if(selects.length === i) return doMoreWork(); // if no selects left, abort and do more work
    $.when(doWork(selects.get(i)).then(function() { // fetch and do next if completed
        doItem(i + 1);
    });
});

doItem(0); // start process

答案 6 :(得分:-1)

因为看起来你在做jQuery,你可以使用$ .ajaxStop事件处理程序...... http://api.jquery.com/ajaxStop/

编辑说$ .ajaxComplete而不是正确的$ .ajaxStop ...现在修复...