顺序延迟的承诺与ajax调用乱序运行

时间:2014-09-16 19:15:56

标签: javascript jquery ajax

如果你看一下showResults(),你会看到它首先创建一个promise,然后运行getSelectedIds()返回一个promise,然后它用那些选中的id进行api调用,这是一个ajax调用,然后是控制台日志sr df3 finished。我有一个极难的时间搞清楚的问题是我认为我在某处有一些遗漏的回复陈述,所以承诺得到过早解决或某事。

有人可以在这里找出我出错的地方,并告诉我在getApi ajax调用或之前或之后的事件中需要什么,以便" sr df3完成"直到ajax调用返回其承诺之后才会发生。

app.core.getSelectedIds = function(){

    var dfd = $.Deferred();

    //eliminates having to make an unnecessary ajax call if we already have them
    if( $.isEmptyObject(app.core.selectedIds) ){

        //gather up selected ids
        $('input[type=checkbox]').each(function (key, value) {

            //look for checked checkboxes only
            if ($(this).is(':checked') && $(this).hasClass('results')) {

                //get id from hidden input next to checkbox, set ids into an object for later use
                stdIds[key] = $(this).next().attr('value');
            }
        });

        app.core.selectedIds = stdIds;
    }

    dfd.resolve();
    return dfd.promise();
};

 app.test.getApi = function(newToken, nextPageNum){

    var df1,df2;

    if(nextPageNum){ app.test.nextPageNum = nextPageNum; }

    df1 = app.test.ajaxCall1();

    df2 = df1.then( function(){
            console.log('test df2 started');
            console.log(app.test.standardsObj); //the ajax calls results after being applied to the methods property
    });

    df2.done(function(){
            console.log('test df2 finished');
    });
};

app.ui.showResults = function(newToken){

    var df1,df2,df3;

    df1 = $.Deferred();

    df2 = df1.then(function(){
            console.log('sr df2 started');
            return app.core.getSelectedIds(); //is a promise
    });

    df2.done(function(){
            console.log(app.core.selectedIds);
            console.log('sr df2 finished');
    });

    df3 = df2.then(function(){
            console.log('sr df3 started');
            app.test.getApi(newToken);
    });

    df3.done(function(){
            console.log('sr df3 finished');
    });

    df1.resolve();
};

app.test.ajaxCall1 = function(){

    var idArr = [];

    //For now set up an array to cast those values to
    $.each(app.core.selectedIds, function( key, value ){

        idArr[key] = value;
    });

    return app.core.methodByRoute('ajax_call_1', {ids: idArr}, 'GET')
        .done(function(retrievedResults){

            app.test.standardsObj = retrievedResults;
        })
};

控制台日志输出

sr df2 started
Object { 1="498", 2="501", 3="502", more...}
sr df2 finished 
sr df3 started 
sr df3 finished 
test df2 started 
["valid data"] 
test df2 finished

1 个答案:

答案 0 :(得分:1)

app.core.getSelectedIds = function(){
    var dfd = $.Deferred();
    …
    dfd.resolve();
    return dfd.promise();
}

看起来这个函数根本不需要异步返回一个promise,并且无论如何都会立即解决deferred?

  

我想我某处遗漏了一些回复陈述

是的,确切地说。基本规则是: return来自执行异步的每个函数的承诺。在您的情况下,包括app.test.getApi函数和调用它的df2.then(function(){…})回调 - 如果回调没有返回任何内容,df3会在df2之后立即解析,它不知道该等什么。

顺便说一句,你不需要那个df1 - 只需用函数返回的第一个承诺来启动链。

app.core.getSelectedIds = function() {
    if ($.isEmptyObject(app.core.selectedIds)) {
        $('input[type=checkbox]').each(function (key, value) {
            if ($(this).is(':checked') && $(this).hasClass('results')) {
                stdIds[key] = $(this).next().attr('value');
            }
        });
        app.core.selectedIds = stdIds;
    }
    return $.when(app.core.selectedIds); // a promise. just to start the chain.
                                         // maybe this function needs to do
                                         // something async in the future
};

app.test.getApi = function(newToken, nextPageNum) {
    if (nextPageNum) {
        app.test.nextPageNum = nextPageNum;
    }
    var df1 = app.test.ajaxCall1();
    var df2 = df1.then( function(){
            console.log('test df2 started');
            console.log(app.test.standardsObj); //the ajax calls results after being applied to the methods property
    });
    df2.done(function(){
            console.log('test df2 finished');
    });
    return df2;
//  ^^^^^^^^^^^
};

app.ui.showResults = function(newToken) {
    var df1 =app.core.getSelectedIds(); // is a promise
    df1.done(function() {
        console.log(app.core.selectedIds);
        console.log('sr df2 finished');
    });
    var df2 = df1.then(function() {
        console.log('sr df2 started');
        return app.test.getApi(newToken);
//      ^^^^^^
    });
    df2.done(function(){
        console.log('sr df2 finished');
    });
    return df2;
//  ^^^^^^^^^^^ just for convenience, if we want to chain something
//              after a .showResults() call
};