Javascript: Сохранить AJAX Результат как переменная класса

Я знаю, что javascript не использует Class, по крайней мере, не в здравом смысле`. Я хотел бы знать, как вернуть и сохранить возвращаемое значение AJAX в переменной класса, а не вызывать несколько методов в обратном вызове.

var Reader = function(){
  //Initialize some variables
  this.data = null;
}

Reader.prototype.makeAjaxCall = function(urlPath){
   //Make and Ajax call and return some value
   Ajax.success(function(data){
     this.data = data;
   });
}

Reader.prototype.searchData = function(param){
   //Needs access to this.data
}
Reader.prototype.findData = function(id){
  //Needs access to this.data
}

Reader.prototype.deleteItem = function(id){
  // Needs access to this.data
}

В приведенном выше коде любая функция, которая нуждается в доступе к свойству data, должна быть вызвана в ajax success callback, поэтому, если у меня есть десять методов, которые нуждаются в данных, мне придется выровнять их все в пределах обратный вызов, который я не чувствую, прав. Как свести к минимуму количество функций в обратном вызове и обеспечить некоторыми другими способами успешную работу функции и сохранение данных переменной экземпляра data.

Ответ 1

Сущностная часть - это то, как обрабатывать асинхронные данные с помощью JavaScript. Для этого есть несколько хорошо протестированных решений: функции и promises.

В обоих cass Reader должен иметь конструктор, который присваивает данные следующим образом:

function Reader(data) {
   this.data = data;
}

Для метода обратного вызова требуется функция factory, которая имеет обратный вызов.

function getReader(url, callBack) {
   Ajax.success(function(data){
      callBack( new Reader(data) );
   });
}

И используйте его как

getReader(url, function(reader) {
    reader.searchData();
});

Promise-Approach не требует немедленного обратного вызова, поэтому результат может быть сохранен в переменной и передан как переменная, которая имеет некоторые преимущества:

function getReaderPromise(url) {
   return new Promise( function( resolve, reject ) {
     Ajax.success(function(data){
      resolve( new Reader(data) );
     });    
   });
}

Однако использование обещания обычно требует вызова функции then обещания:

getReaderPromise(url).then( function(reader) {
    reader.searchData();
});
// Fat arrow syntax
getReaderPromise(url).then( (reader) => {
    reader.searchData();
});  

В будущем вы можете избавиться от обратных вызовов с помощью Promises с помощью генераторов ES6 с выходом вроде

let reader = yield getReaderPromise( url );

Как объясняется здесь: https://davidwalsh.name/async-generators

Ответ 2

Вы можете попробовать что-то вроде:

var Reader = function(){
  //Initialize some variables
  this.data = null;
}

Reader.prototype.makeAjaxCall = function(urlPath){
   //Make and Ajax call and return some value
   this.data = Ajax({url: urlPath}); // return promise
}

Reader.prototype.searchData = function(param){
   //Needs access to this.data
   if(this.data){
       this.data.then(...);
   }

}
Reader.prototype.findData = function(id){
  //Needs access to this.data
   if(this.data){
       this.data.then(...);
   }
}

Reader.prototype.deleteItem = function(id){
  // Needs access to this.data
   if(this.data){
       this.data.then(...);
   }
}

Ответ 3

В вашем коде:

Reader.prototype.makeAjaxCall = function(urlPath){
   //Make and Ajax call and return some value
   Ajax.success(function(data){
     this.data = data;
   });
}

"this" не является контекстом экземпляра Reader, вы должны изменить его на

Reader.prototype.makeAjaxCall = function(urlPath){
   var myThis = this;
   //Make and Ajax call and return some value
   Ajax.success(function(data){
     myThis .data = data;
   });
}

Чтобы сохранить указатель на экземпляр Reader в переменной myThis и получить доступ к функции успеха

Ответ 4

это то, что я считаю хорошим способом его решения, ему нужно несколько обратных вызовов, хотя

var Reader = function(){
  //Initialize some variables
  this.data = null;
}

Reader.prototype.makeAjaxCall = function(urlPath, cb) {
   //Make and Ajax call and return some value
   Ajax.success(function(data) {
     this.data = data;
     if(cb) cb();
   });
}

Reader.prototype.searchData = function(param){
    var self = this;
    if(!this.data) {
        // data doesn't exist, make request
        this.makeAjaxCall(urlPath, function() {
            // when is ready, retry
            self.searchData(param);
        });
        return;
    }
   // do whatever you need...
   // data exists
}
Reader.prototype.findData = function(id){
    var self = this;
    if(!this.data) {
        // data doesn't exist, make request
        this.makeAjaxCall(urlPath, function() {
            // when is ready, retry
            self.findData(id);
        });
        return;
    }
   // do whatever you need...
   // data exists
}

Reader.prototype.deleteItem = function(id){
    var self = this;
    if(!this.data) {
        // data doesn't exist, make request
        this.makeAjaxCall(urlPath, function() {
            // when is ready, retry
            self.deleteItem(id);
        });
        return;
    }
   // do whatever you need...
   // data exists
}

Ответ 5

Ваша проблема связана с путаницей в 'this'.

Когда вы используете это в функции, он использует контекст этой функции.

Итак, это немного использует другой контекст:

Reader.prototype.makeAjaxCall = function(urlPath){
   //Make and Ajax call and return some value
   Ajax.success(function(data){
     this.data = data;
   });
}

чем это:

Reader.prototype.makeAjaxCall = function(urlPath){
   var readerContext = this;
   //Make and Ajax call and return some value
   Ajax.success(function(data){
     readerContext.data = data;
   });
}

и это решение вашей проблемы.

Ответ 6

Вы можете сделать что-то вроде

 Reader.prototype.searchData = function(param){
    var self = this;
    if (!this.data) {
       setTimeout(function() { self.searchData(param) }, 1000);
       return;
    }
    ...
 }

Ответ 7

Попробуйте изменить это:

Reader.prototype.makeAjaxCall = function(urlPath){
   //Make and Ajax call and return some value
   Ajax.success(function(data){
     this.data = data;
   });
}

:

Reader.prototype.makeAjaxCall = function(urlPath){
  var _this = this;

   //Make and Ajax call and return some value
   Ajax.success(function(data){
     _this.data = data;
   });
}

Ответ 8

Одним простым решением было бы поместить все вызовы функций в другую функцию и вызвать только вызов из обратного вызова:

var Reader = function(){
  //Initialize some variables
  this.data = null;
}

Reader.prototype.makeAjaxCall = function(urlPath){
   //Make and Ajax call and return some value
   var that = this;
   Ajax.success(function(data){
     that.data = data;
     that.makeOtherCalls();
   });
};


Reader.prototype.makeOtherCalls = function(){

    // call the functions that need this.data here

};

Ответ 9

Вы можете использовать context настройку $.ajax(), чтобы установить this в $.ajax() обратный вызов, deferred.then(); включить функцию обработки ошибок в экземпляр Reader.

// set `this` at `$.ajax()` to context of `Reader` instance
var Reader = function(context) {

  //Initialize some variables
  this.data = null;

  // handle `$.ajax()` errors
  this.err = function(jqxhr, textStatus, errorThrown) {
    console.log(textStatus, errorThrown, this);
  }

  this.makeAjaxCall = function(urlPath) {
    //Make and Ajax call and return some value
    return $.ajax({
        url: urlPath,
        // set `context` to `this`
        context: context || this,
      })
      .then(function(data) {
        this.data = data;
        console.log("in `Reader.makeAjaxCall`, this is:", this);
      }, this.err);
  }

  this.searchData = function(param) {
    //Needs access to this.data
    console.log("in `Reader.searchData`", this.data);
  }

  this.findData = function(id) {
    //Needs access to this.data
    console.log("in `Reader.findData`", this.data);
  }

  this.deleteItem = function(id) {
    // Needs access to this.data
    console.log("in `Reader.deleteItem`", this.data);
  }

}

var reader = new Reader();

reader.makeAjaxCall("")
.then(reader.searchData)
.then(reader.findData)
.then(reader.deleteItem)
.then(function() {
    console.log("complete", this.data, this)
})

Ответ 10

люди одержимы использованием прототипов для создания функций внутри класса, но есть более чистый способ, используя функции с ссылкой 'this'. Затем вы можете получить доступ к внутренней работе вашего класса через переменную self.

например:

var Reader = function(){
    var self = this;

    //Initialize some variables
    this.data = null;

    this.makeAjaxCall = function(urlPath){  
       Ajax.success(function(data){
         self.data = data;
       });
    }
}

Затем в ваших методах прототипа вы можете использовать данные с помощью:

this.data

Вы можете вызвать метод ajax, используя:

this.makeAjaxCall(url);

И вы можете вызвать метод ajax извне класса, используя:

var myReader = new Reader();
myReader.makeAjaxCall(url);

согласно нормали.

Ответ 11

СДЕЛАТЬ ИСПОЛЬЗОВАНИЕ ГЛОБАЛЬНОЙ ПЕРЕМЕННОЙ JS

Вы можете просто использовать глобальные переменные JS для такого рода требований. Пожалуйста, проверьте код ниже

var globalData; /* This is global.It can be accessed anywhere */
var Reader = function(){
  //Initialize some variables
  globalData = null;
}

Reader.prototype.makeAjaxCall = function(urlPath){
   //Make and Ajax call and return some value
   Ajax.success(function(data){
     globalData = data;
   });
}

Reader.prototype.searchData = function(param){
   //Access globalData here
}
Reader.prototype.findData = function(id){
  //Access globalData here
}

Reader.prototype.deleteItem = function(id){
  //Access globalData here
}

Ответ 12

Чтобы сохранить возвращаемые данные в так называемой переменной Class, учитывая ваш пример, вам нужно понять контекст, в котором вы используете ключевое слово this. В вашем примере

Reader.prototype.makeAjaxCall = function(urlPath){
   //Make and Ajax call and return some value
   Ajax.success(function(data){
     this.data = data;
   });
}

this относится к объекту Ajax.

Так как this.data в объекте Reader в значительной степени инкапсулируется в контексте объекта Reader, вам необходимо сохранить его локально перед вызовом Ajax, чтобы иметь возможность получить к нему доступ с помощью вызова. Вот так:

Reader.prototype.makeAjaxCall = function(urlPath){
    var _this = this;
   //Make and Ajax call and return some value
   Ajax.success(function(data){
     _this.data = data;
   });
}

Это в значительной степени решает проблему контекста и очень полезно, когда дело доходит до выполнения вызовов функций. Простое решение состоит в том, чтобы просто определить локальную переменную, в которой вы можете временно хранить данные, а затем использовать их для перезаписывания значения this.data Код должен выглядеть следующим образом:

 Reader.prototype.makeAjaxCall = function(urlPath){
        var tempData;
       //Make and Ajax call and return some value
       Ajax.success(function(data){
         tempData = data;
       });
       this.data = tempData;
    }

Ответ 13

Я разработал для этого свою собственную jQuery ajax-оболочку, но для нее требуется jQuery... Если это поможет проверить мое репозиционирование github

JQPS Framework v. 1.1b - Github

Это может помочь вам, он использует OOP по пространствам имен (классы, которые вы ищете), например Myobject.vars.anything = value (from callback)

Пример вызова

Main.ajaxCall('auth','login','POST','TEXT',{dataObj},{Utils:{1:'setVar|Main,myVar,,callback',2:'anyOtherFunction'}},false);

Это вызовет ajax-вызов http://yoursite.com/auth/login с dataObj в качестве объекта post, при обратном вызове будет вызвана первая функция, в нашем случае Utils.setVar() это сохранит ответ от обратного вызова в Main.vars.myVar, как мы определили его в объекте обратного вызова, после чего вторая функция будет запущена и выполнена, как определено в вызове Utils.anyOtherFunction(). вы можете добавить, сколько функций вы хотите в обратном вызове.

Для получения дополнительной информации вы можете проверить readme из github, это настроено на вызовы синхронизации и асинхронного вызова, но для этого требуется jQuery, он не работает без него.