尝试使用面向对象的javascript和AJAX

Trying to use object oriented javascript and AJAX

本文关键字:javascript AJAX 面向对象的      更新时间:2024-04-12

我正在尝试使用一些面向对象的Javascript来保持代码的整洁,而不是像往常一样使用一个巨大而混乱的脚本。使用Ajax使这一过程变得复杂,因为它具有异步性质,很难分离代码。

我遇到的一个具体问题是使用Ajax设置对象属性。

我有以下代码:

var Class = function(){
  this.attr1;
}
Class.prototype.setAttr1 = function(){
  var self = this;   
  $.ajax({
    url:'http://api.something.com?get=somedata',
    success: function(data){
      self.attr1 = data.name;
    }
  });
}

这应该有效,但如果我从其他地方访问该属性,我真的不能确定它是否已设置,对吗?有办法解决这个问题吗。比如,如果我需要在某个地方使用attr1,我可以等待ajax返回吗?或者,如果我完全不喜欢,人们在使用Ajax时如何封装代码?

这应该有效,但如果我从其他地方访问该属性,我真的不能确定它是否已设置,对吗?

纠正

有办法解决这个问题吗。比如,如果我需要在某个地方使用attr1,我可以等待ajax返回吗?

是的:如果要使用attr,请让访问器接受回调(直接或通过返回promise间接),并在属性可用时让它调用回调(或解析promise)。

看起来您希望将启动ajax调用的代码与稍后使用属性值的代码分开。如果是这样的话,在这种情况下,基于承诺的机制可能会更有用。在使用jQuery时,这里有一个使用jQuery的DeferredPromise:的jQuery示例

var Class = function(){
  this.attr1LoadDeferred = $.Deferred();
}
Class.prototype.setAttr1 = function(){
  var self = this;   
  $.ajax({
    url:'http://api.something.com?get=somedata',
    success: function(data){
      self.attr1 = data.name;
      self.attr1LoadDeferred.resolveWith(self);
    }
  });
}
Class.prototype.accessAttr1 = function() {
    return this.attr1LoadDeferred.promise();
};

用法:

// Create an instance
var c = new Class();
// At some point, initiate loading the value
c.setAttr1();
// At some point, look to use the value
c.accessAttr1().then(function(inst) {
    console.log(inst.attr1);
});
// Somewhere else, look to use the value
c.accessAttr1().then(function(inst) {
    doSomethingElseWith(inst.attr1);
});

不幸的是,jQuery的Deferred/Promise实现有一个大多数promise库都没有的问题:传递给then的回调有时会被异步调用,有时会被同步调用。(特别是:如果promise已经被解析,那么回调是同步的。)使用它时请记住这一点,或者使用不同的promise实现。

通常,您可以:

  • 传递回调或承诺,让代码等待设置值;jQuery框架大量使用回调,但也从其AJAX函数中返回promise。

  • 使对象在属性更改时引发事件。Backbone是大量使用事件的框架的一个很好的例子。

将需要使用attr1的代码作为回调传递:

Class.prototype.setAttr1 = function(callback){
  var self = this;   
  $.ajax({
    url:'http://api.something.com?get=somedata',
    success: function(data){
      self.attr1 = data.name;
      if (callback)
        callback(self);
    }
  });
}