1

因此,我尝试在 Web 应用程序上使用 $.Deferred 对象来确保在尝试执行 [目标] 之前已完成 [先决条件]。

长话短说,我想用它的真实代码看起来像......

function QuoteReview(openQuote) {
    //constants
    this.RETIRE_AFTER=180; //...seconds. Do not use cached values older than this, instead, reload them
    this.lastLoadedQuotes=undefined;
    this.quotes=[];
    this.currentQuote={
        chosen:false, 
        id:undefined, 
        loaded:false, 
        name:undefined,
        pricebook:undefined,
        prontoId:undefined,
        state:undefined,
        reviewer:undefined,
        opportunityId:undefined,
        accountCode:undefined,
        items:[],
        lastLoad:undefined 
    };
    var _curQuote=this.currentQuote;
    this.displayQuote=function(forceLoad) {
        //if forceLoad was specified as true, the quote has never been loaded, or the last load is past it's retirement age, load it first
        if (forceLoad || typeof this.currentQuote.lastLoad == "undefined" || ((new Date() - this.currentQuote.lastLoad)/1000)>this.RETIRE_AFTER)
            this.loadQuote().then(this._displayQuote);
        else
            this.displayQuote();
    }
    this._displayQuote=function() {
        console.log(this); //Displays the deferred object
        console.log(self); //reference error (expected)
        console.log(currentQuote); //reference error
        console.log(_curQuote); //reference error
    }
    this.loadQuote=function() {
        if (this.currentQuote.chosen) {
            var self=this;
            return $.getJSON("queries/getQuote.php?id="+encodeURIComponent(this.currentQuote.id),function(data) {
                //TODO add in the error/logged out handling
                data=data.data[0];
                self.currentQuote.name=data.name;
                self.currentQuote.pricebook=data.pricebook;
                self.currentQuote.prontoId=data.prontoId;
                self.currentQuote.state=data.state;
                self.currentQuote.reviewer=data.reviewer;
                self.currentQuote.opportunityId=data.opportunityId;
                self.currentQuote.accountCode=data.accountCode;
                self.currentQuote.items=data.items;
                self.currentQuote.lastLoad=new Date();
                self.currentQuote.loaded=true;
            });
        } else {
            console.log("tried to load quote before it was chosen!");
            return $.Deferred();
        }
    }
}

但我制作了一些测试代码来更容易地显示问题:

function getSomeAjax() {
    return $.getJSON("queries/quoteSearch.php?needle=",function(data) {
        console.log("got the response");
        console.log(data);
        window.someInfo=data;
    });
}
function _useIt() {
    console.log("we would use the data here, doing some dom type stuff");
    console.log(window.someInfo);
    console.log(this);
}
function useIt() {
    getSomeAjax().then(_useIt);
}

(该查询只返回一些数据......在这种情况下并不重要,我们不做任何事情)

问题是,当我登录this_useIt()函数时,我看到了延迟对象的范围。现在这是完全有道理的,我当时正在调用 - 延迟对象的成员,但是有人知道解决这个问题的方法吗?如果我使用.apply(window,[])它似乎甚至不会调用 _useIt。现在,看到我只是quoteReview = new QuoteReview();在页面上使用并且我将始终只有一个 QuoteReview 对象,我知道我可以做quoteReview.currentQuote而不是this.currentQuote,如果推来推去我不介意这样做,但我也会想知道这样做的正确方法。

回答后编辑:在这种情况下,我最终使用了 Travis 和 Esthete 的答案组合。我发现 Aesthete 在回调函数中为我工作,但后来我意识到我还需要创建一个_curParts,_curQuotes_curPart变量;我也使用了一个var self=thisassigned insideloadQuote()来访问匿名ajax函数中的成员,但这似乎是双重工作(考虑到self还具有的所有属性_curQuote)。相反,我var self=this在整个构造函数的范围内使用它来访问匿名 ajax 函数和.then()作为回调传递的函数中的成员。

4

3 回答 3

3

您应该能够使用闭包来解决问题,尽管我认为这不是最好的解决方案。

var _curQuote = this.currentQuote;
this._displayQuote=function() {
  // Use _curQuote, which should just reference the member currentQuote.
}

看看这个 fiddle,它应该有望消除一些混乱。

于 2013-04-11T01:07:02.113 回答
1

您需要使用闭包和一个新的作用域变量。 this取决于调用上下文,并将被分配给您所看到的 jQuery 对象。

您可以尝试这样的事情(从您的代码中截取):

this.loadQuote=function() {
    var self = this; // This is grabbing the correct context
    return $.getJSON("local/address.php",function(data){
        //success handler. Fills in the this.currentQuote object
        // Here you'll want to use self.currentQuote
    });
}

编辑:我想提供一些样本来澄清一些评论。我个人的偏好是 Underscore.js 绑定方法。如果您不使用该框架,则可以包含您自己的该方法版本并将其扔到函数原型上以进行更清晰的调用。

var MyClass = function() {
    this.MyVariable = "Hello World";

    this.MyCallback = function(data) {
        alert(this.MyVariable);
    };

    // Using 'self' variable to preserve invocation context
    //    The important thing is that 'self' is LOCAL ONLY
    //    and the MyCallback method can reliably rely on 'this'
    this.MakeCallSelfVariable = function() {
        var self = this;
        return $.getJSON("url", function(data) {
            self.MyCallback(data);
        }
    };

    // Using Underscore.js _.bind()
    this.MakeCallUnderscore = function() {
        return $.getJSON("url", _.bind(this.MyCallback, this));
    };

    // Using jQuery's options to set the context (obviously
    //    depends on jQuery
    this.MakeCallJQuery = function() {
        return $.ajax({
            dataType: "json",
            url: "url",
            context: this, // Important line
            success: function(data) {
                // Here, 'this' will refer to what you
                //    assigned to context
                this.MyCallback(data);
            }
        });
    };
};
于 2013-04-11T01:10:13.097 回答
1

的含义this并不总是很明显,我不想猜测它是什么_useIt()。它可以是全局名称空间或其中的任何内容,具体取决于代码的组织方式。

this且不说,处理代码的第一件事是避免data通过全局成员传递。AsgetSomeAjax()返回一个符合 Promise 的 jqXHR,data自动传递给 chained.then().done()handlers。

例如,您的代码将简化如下:

function getSomeAjax() {
    return $.getJSON("queries/quoteSearch.php?needle=", function(data) {
        console.log("got the response");
        console.log(data);
    });
}
function _useIt(data) {
    console.log("we would use the data here, doing some dom type stuff");
    console.log(data);
}
function useIt() {
    getSomeAjax().then(_useIt);
}

...,这可能更容易理解_useIt匿名写:

function getSomeAjax() {
    return $.getJSON("queries/quoteSearch.php?needle=", function(data) {
        console.log("got the response");
        console.log(data);
    });
}
function useIt() {
    getSomeAjax().then(function(data) {
        console.log("we would use the data here, doing some dom type stuff");
        console.log(data);
    });
}

请注意,它data作为匿名函数的第一个参数出现的方式与它作为$.getJSON()回调的第一个参数出现的方式相同。第二个和第三个参数在这两个函数中同样可用。

此外,这里的力量.then()可能不是必需的。.done()将完成这项工作,除非您需要通过返回一个新值或一个新的 Promise 来过滤 Promise,以便向下传递一个扩展的方法链,例如。getSomeAjax(...).then(...).then(...).done(...).fail(...).always(...).

于 2013-04-11T02:43:15.947 回答