【问题标题】:jQuery Deferred then() called before resolvedjQuery Deferred then() 在解决之前调用
【发布时间】:2014-08-26 18:15:16
【问题描述】:

我是 jQuery Deferred 的新手,不明白为什么在成功函数完成之前调用 then。我有两个同时的 ajax 请求,并希望触发 UI 单选按钮单击以迭代从其中一个 ajax 调用返回的一些数据,这需要 20 秒才能响应。但是,当在 then() 中触发单选按钮单击时,要迭代的数据为空。如果我单击不同的单选按钮来过滤数据,然后单击触发的单选按钮,则数据不为空,因为已经过了足够的时间来成功加载对象。

对象在第一个(20 秒)ajax 调用成功加载,然后在 then() 中触发点击,当这两个调用都解决时。为什么 then() 还没有成功触发点击?

    firstAjaxFunc: function(args){          
        return $.ajax({
            type: "POST",               
            url: REQUEST_URL + "/first-func",
            contentType: "application/json",
            data: $.toJSON({
                propOne: propOne,
                propTwo: propTwo
            }),
            dataType: "json class.models",
            context: args.context,
            success: args.success,
            error: showResponseError
        });
    },

    secondAjaxFunc: function(args){
        return $.ajax({
            type: "POST",               
            url: REQUEST_URL + "/second-func",
            contentType: "application/json",
            data: $.toJSON({
                propOne: propOne,
                propTwo: propTwo
            }),
            dataType: "json class.models",
            context: args.context,
            success: args.success,
            error: showResponseError
        });
    },

        $('#load-data').append('<p class="spinner" align="center"><img src="../images/loading_small.gif"/></p>');
        this.firstAjaxFunc({
            params: {
                propOne: propOne,
                propTwo: propTwo
            },
            success: function(data){
                this.options.stuff = data;
            },
            context: this
        });
        this.secondAjaxFunc({
            params: {
                propOne: propOne,
                propTwo: propTwo
            },
            success: function(data){
                this.options.moreStuff = data;
            },
            context: this
        });
        $.when(firstAjaxFunc, secondAjaxFunc).then(this.find(".filter-all").click());

    ".filter-all click": function(radio, event){ 
            this.showAllData();
    },

    showAllData: function(){
        for(var i = 0; i < this.options.stuff.length; i++){ // this.options.stuff is null
            $.merge(stuffArr, this.options.stuff[i].getMyStuff());
        }
    },

【问题讨论】:

  • firstAjaxFunc 不包含您认为的内容。
  • 你到底为什么在这里到处使用this?这会导致错误,就像使用常规变量一样多的代码。
  • @GeorgeMauer,这是别人的代码,我刚开始做这个项目。
  • 这工作:$.when(promiseOne, promiseTwo).done(function () { console.log('promiseOne and promiseTwo are done');$('.filter-all').click()}).fail(function () { console.log('One of our promises failed'); });
  • 一般来说,最好不要将成功处理程序与 promise .then().done() 处理程序混合使用。如果您正在使用 Promise,那么请在任何地方使用 Promise,并且不要使用成功处理程序。这使得事情被调用的时间全部按照 Promise 规范(时间和顺序非常明确)。我建议您将成功和错误处理程序更改为在您的 ajax 承诺上使用 .then(),以便您执行 return $.ajax(...).then(args.success, showResponseError); 并删除 successerror 处理程序。然后,您必须修复 this 的使用。

标签: jquery ajax jquery-deferred


【解决方案1】:

我看到两个主要问题。

$.when() 接受 Promise 作为参数,而不是回调函数。因此,您需要像这样实际调用传递给它的函数:

 $.when(this.firstAjaxFunc(...), this.secondAjaxFunc(...)).then(...);

并且,.then() 处理程序必须是回调函数,因此您必须将 .then() 处理程序转换为可以稍后调用的回调函数。正如您现在所拥有的那样,它会立即执行并将其结果传递给.then(),这就解释了为什么.click() 会立即执行。


此外,最好不要将 jQuery 成功处理程序与承诺处理程序混用。选择其中一个并始终如一地使用它们。在这种情况下,由于您需要一些 Promise 功能,您可能应该只使用 Promise,因为 Promise 处理程序的调用顺序和序列在 Promise 规范中进行了严格描述,因此调用顺序不会有歧义。


您只显示代码片段,因此很难获得完整的上下文,但我认为您想要这样的东西:

    var p1 = this.firstAjaxFunc({
        params: {
            propOne: propOne,
            propTwo: propTwo
        },
        success: function(data){
            this.options.stuff = data;
        },
        context: this
    });
    var p2 = this.secondAjaxFunc({
        params: {
            propOne: propOne,
            propTwo: propTwo
        },
        success: function(data){
            this.options.moreStuff = data;
        },
        context: this
    });
    $.when(p1, p2).then(function() {
        this.find(".filter-all").click();
    }, showResponseError);

或者,将所有内容都转换为承诺:

    var self = this;
    var p1 = this.firstAjaxFunc({
        params: {
            propOne: propOne,
            propTwo: propTwo
        }
    });
    var p2 = this.secondAjaxFunc({
        params: {
            propOne: propOne,
            propTwo: propTwo
        }
    });
    $.when(p1, p2).then(function(data1, data2) {
        // process the results
        self.options.stuff = data1[0];
        self.options.moreStuff = data2[0];

        // carry out action now that both are done
        this.find(".filter-all").click();
    }, showResponseError);

【讨论】:

  • 是的,这几乎就是我最终要做的事情。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-31
  • 2020-12-27
  • 1970-01-01
  • 1970-01-01
  • 2019-02-27
  • 1970-01-01
相关资源
最近更新 更多