2013-04-25 3 views
0

Я разрабатываю клиентскую библиотеку для веб-службы, и у меня возникают некоторые проблемы с установкой переменной объекта и последующим ее получением.Проблема с операцией Async Установка свойства объекта в JS

Вот начало библиотеки

var QuickBase = function(username, password, apptoken, realm) { 

    this.username = username; 
    this.password = password; 
    this.apptoken = (typeof apptoken === "undefined") ? '' : apptoken; 
    this.realm = (typeof realm === "undefined") ? 'www' : realm; 
    this.ticket = ''; 
    this.dbid = ''; 
    this.payload = '<qdbapi>'; 

    this.init = function() { 
     var self = this; 

     this.authenticate(this.username, this.password, null, null, function(data) { 
      var errcode = $(data).find('errcode').text(); 
      if(errcode > 0) 
       throw new Error($(data).find('errtext').text()); 

      self.ticket = $(data).find('ticket').text(); 
     }); 
    } 

    this.setBaseUrl = function() { 
     var endpoint = this.dbid == '' ? 'main' : this.dbid; 
     this.baseUrl = 'https://' + this.realm + '.quickbase.com/db/' + endpoint; 
    } 

    this.transmit = function(method, callback) { 
     this.setBaseUrl(); 

     if(this.apptoken) 
      this.payload += '<apptoken>' + this.apptoken + '</apptoken>'; 

     if(this.ticket) 
      this.payload += '<ticket>' + this.ticket + '</ticket>'; 

     this.payload += '</qdbapi>'; 

     console.log(this.payload); 

     $.ajax({ 
      url: this.baseUrl, 
      type: 'POST', 
      data: this.payload, 
      dataType: 'xml', 
      headers: { 
       'Content-Type': 'application/xml', 
       'QUICKBASE-ACTION': method 
      }, 
      success: callback 
     }); 

     this.payload = '<qdbapi>'; 
    } 

    this.addSettingsToPayload = function(settings) { 
     for(var key in settings) { 
      this.payload += '<' + key + '>' + settings[key] + '</' + key + '>'; 
     } 
    } 

    this.authenticate = function(username, password, hours, udata, callback) { 
     this.payload += '<username>' + username + '</username>'; 
     this.payload += '<password>' + password + '</password>'; 

     this.payload += (typeof hours === "undefined") ? '' : '<hours>' + hours + '</hours>'; 
     this.payload += (typeof udata === "undefined") ? '' : '<udata>' + udata + '</udata>'; 

     this.transmit('API_Authenticate', callback); 
    } 

И вот случай использования:

вар имя пользователя = 'Foo', пароль = 'бар', маркер = 'footoken', realm = 'foorealm';

window.qb = new QuickBase(username, password, token, realm); 
$.when(qb.init()).then(function(){ 
    console.log(qb); // shows the object with ticket set 
    console.log(qb.ticket); // empty 
    qb.doQuery(); // breaks because internal this.ticket is empty 
}); 

Поэтому мой вопрос в том, почему qb.ticket не устанавливается и недоступен в будущих вызовах функций?

Кроме того, есть способ, которым мне не нужно обертывать .init() в .when?

В принципе, init устанавливает билет, который потребует все будущие методы API. Если я просто вызову qb.init(), а затем qb.doQuery(), то нет гарантии, что init() будет завершен, но если я буду использовать .when, это не означает, что все будущие вызовы метода должны быть внутри .then callback? Это кажется уродливым.

+0

'someMethod' вероятно запущен до' init' отделки. Переместите 'someMethod' в закрытие, и все будет хорошо. –

+0

Не совсем. Это не отвечает на то, почему console.log (s.ticket) возвращает пустым, в то время как выведенный выше результат показывает его как заданный. – doremi

+1

Пожалуйста, опубликуйте реализацию 's.init'. –

ответ

0

$.when ожидает обещать объект. Если он не получит один, он немедленно выполнит обратный вызов. Вы должны вернуть обещание от $.ajax позвонить или создать свой собственный.

Но поскольку вы работаете только с одним обещанием, вам даже не нужно, когда. Вы можете сделать:

qb.init().done(qb.doQuery.bind(qb)); 

Пример:

var QuickBase = function(username, password, apptoken, realm) { 
    // ... 

    this.init = function() { 
     var self = this; 

     return this.authenticate(this.username, this.password, null, null).done(function(data) { 
      var errcode = $(data).find('errcode').text(); 
      if(errcode > 0) 
       throw new Error($(data).find('errtext').text()); 

      self.ticket = $(data).find('ticket').text(); 
     }); 
    } 

    this.transmit = function(method) { 
     // ... 

     var promise = $.ajax({ 
      url: this.baseUrl, 
      type: 'POST', 
      data: this.payload, 
      dataType: 'xml', 
      headers: { 
       'Content-Type': 'application/xml', 
       'QUICKBASE-ACTION': method 
      } 
     }); 

     this.payload = '<qdbapi>'; 
     return promise; 
    } 

    this.authenticate = function(username, password, hours, udata) { 
     // .. 
     return this.transmit('API_Authenticate'); 
    } 
} 

Как альтернатива, вы можете просто сделать .init принять обратный вызов:

this.init = function(callback) { 
    var self = this; 

    this.authenticate(this.username, this.password, null, null, function(data) { 
     var errcode = $(data).find('errcode').text(); 
     if(errcode > 0) 
      throw new Error($(data).find('errtext').text()); 

     self.ticket = $(data).find('ticket').text(); 
     callback(); 
    }); 
}; 

, а затем:

qb.init(function(){ 
    qb.doQuery(); 
}); 
+0

Но вы полностью убили обратный вызов, который передается в качестве аргумента и использовался для вызова? Я думаю, мне нужно это, чтобы пользователь doQuery, например, мог обрабатывать возвращаемые данные, когда он возвращается, не так ли? – doremi

+0

Я сделал? Где? Вы имеете в виду «передать» или «аутентифицировать»?Вам больше не нужен параметр 'callback', потому что вы возвращаете обещание. –

+0

Что это за обещание? Впервые я слышал об этой концепции. – doremi

0

Самый простой подход, вероятно, вернуть обещание от init(), следующим образом:

this.init = function() { 
    var self = this; 
    var dfrd = $.Deferred(); 
    this.authenticate(this.username, this.password, null, null, function(data) { 
     var errcode = $(data).find('errcode').text(); 
     if(errcode > 0) 
      throw new Error($(data).find('errtext').text()); 
     self.ticket = $(data).find('ticket').text(); 
     dfrd.resolve(); 
    }); 
    return dfrd.promise(); 
} 

Тогда:

window.qb = new QuickBase(username, password, token, realm); 
qb.init().then(function() { 
    console.log(qb); 
    console.log(qb.ticket); 
    qb.doQuery(); 
}); 
Смежные вопросы