Jquery Deferred未到达最后一个.then

6

我有一系列必须执行的函数。它们都是按顺序执行的,除了最后一个。d1执行,d2执行,d3执行,然后在d4的resolve之前,done函数内部的代码执行。不知道原因所在。需要帮助。

$(document).ready(function() {
    var d1 = functiond1();
    var d2 = functiond2();
    var d3 = functiond3();
    var d4 = functiond4();

    d1.then(d2).then(d3).then(d4).done(function() {

    //Code here does not wait for d4 to end before executing
    //HELP! 

    });
});

function functiond1() {
    var dfd = $.Deferred();

    //Do stuff here
    //Works in sequence

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


function functiond2() {

    var dfd = $.Deferred();
    params = jQuery.param({
        'parm1': 1,
        'parm2': 2,
        'parm3': 3
    });


    jQuery.getJSON($.webMethoJSONGet1, params).done(function(data) {

        //Do stuff here
        //Works in sequence

        dfd.resolve();

    });

    return dfd.promise();
}

function functiond3() {
    var dfd = $.Deferred();

    //Do stuff here
    //Works in sequence

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

function functiond4() {

    var dfd = $.Deferred();

    params = jQuery.param({
        'parm1': 1,
        'parm2': 2,
        'parm3': 3
    });

    jQuery.getJSON($.webMethoJSONGet2, params).done(function(data) {

        //Do stuff here
        //does not work in sequence

        dfd.resolve();

    });

    return dfd.promise();
}

1
当寻求帮助时,请将您的代码缩进得易读。我已经为您运行了jsbeautifier。 - T.J. Crowder
很好的建议。已按要求完成。关于代码有什么建议吗? - ricardo josé kercadó
1
你为什么把所有的代码都缩进得这么远?我已经帮你修复了,现在右边的部分比必要的还要多。我重新修复了它。 - T.J. Crowder
延迟链放在$(document).ready()里面。这是最后一次修复。 - ricardo josé kercadó
1
不是这样的。你的 getJson.done() 返回一个 Promise,应该是你的函数返回的内容。在其中嵌套另一个 Promise 会完全打破使用 Promise 的目的。 - Jason Rice
显示剩余3条评论
3个回答

1

很难确定你想要使用这些 Promise 做什么。你先调用了所有 4 个函数,然后试图用一堆 then 回调函数将它们链接起来。如果你想按顺序将它们链接在一起,应该像这样:

functiond1()
.then(functiond2)
.then(functiond3)
.then(functiond4)
.done(function() { /* blah */ });

如果你只想在所有操作完成后得到结果,你可以使用$.when
$.when(functiond1(), functiond2(), functiond3(), functiond4())
.then(function(resultd1, resultd2, resultd3, resultd4) { /* blah */ });

另外,在您的函数中,您创建了一个不必要的解决方案的承诺,该承诺在另一个承诺的“完成”回调中被解决。$ .getJSON.done()调用本身返回一个承诺,因此不需要额外的承诺。只需返回从done()返回的承诺即可。抱歉,我没有太多涉及jQuery延迟对象,但它们看起来与标准Promise相似。

1
不,那是错误的 - 你必须传递一个函数引用给.then,而不是立即调用该函数的结果。 - Alnitak
@Alnitak 我已经修复了,在then内部延迟调用该函数。谢谢。 - Jason Rice
是的,我正在调用一些函数,它们每个都返回一个 Promise,在前一个 Promise 未解决之前不应该继续到下一个 Promise,但最后一个 Promise 没有等待解决。 - ricardo josé kercadó

0
为了按顺序运行函数,您需要在 .then 链中传递对函数的 引用,而不是调用这些函数的 结果
例如:
var d1 = functiond1;   // NB: no ()
...

d1.then(d2).then(d3).then(d4).done(...);    
functiond1().then(functiond2).then(functiond3).then(functiond4).done(...)

你的问题的根本原因是直接调用 d4 会导致其已解决的 promise 立即通过 .done 传递,而不考虑 .then 链的早期部分的状态。
此外,你也不应该使用额外的 promises 包装你的 JSON 函数,因为 $.getJSON 已经返回一个 promise,如果 AJAX 查询失败,它将被拒绝。
function functiond4() {
    ...
    return $.getJSON(...);
}

感谢您的回答。请不要关注函数名称。在发布问题之前,我已经将它们从原始名称更改,以强调函数顺序。请相信这些不是我正在使用的名称。 - ricardo josé kercadó

-2

我在一个项目中遇到了同样的问题,使用数组的这个解决方案效果很好:

$(document).ready(function() {
    var pr = [];
    var d1 = functiond1();
    var d2 = functiond2();
    var d3 = functiond3();
    var d4 = functiond4();

    function functiond1() {
        var dfd = $.Deferred();
        pr.push(dfd);

        setTimeout(function(){
            $('body').append('1 resolved <br>');
            dfd.resolve();
        }, 2000);
    }


    function functiond2() {
        var dfd = $.Deferred();
        pr.push(dfd);

        params = jQuery.param({
            'parm1': 1,
            'parm2': 2,
            'parm3': 3
        });

        setTimeout(function(){
            $('body').append('2 resolved <br>');            
            dfd.resolve();
        }, 3000);
    }

    function functiond3() {
        var dfd = $.Deferred();
        pr.push(dfd);

        setTimeout(function(){
            $('body').append('3 resolved <br>');
            dfd.resolve();
        }, 1000);
    }

    function functiond4() {
        var dfd = $.Deferred();
        pr.push(dfd);

        params = jQuery.param({
            'parm1': 1,
            'parm2': 2,
            'parm3': 3
        });

        setTimeout(function(){
            $('body').append('4 resolved <br>');
            dfd.resolve();
        }, 50);
    }

    $.when.apply($, pr).then(function() {
        // do something
        $('body').append('proceed with code execution');
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>


谢谢你的回答。我正在验证。 - ricardo josé kercadó
欢迎您,如果代码无法正常工作,请分享给我们。 - Spidi
注意:此代码将同时运行所有四个函数,在并行执行它们的异步操作后,只有在它们全部完成后才会解决。 - Alnitak
所以是这样的 - 我看错了。那实际上就是他的问题了。 - Alnitak
感谢回复。我希望它们按顺序运行,先运行f1,然后是f2,接着是f3,最后运行f4。 - ricardo josé kercadó
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接