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, он не работает без него.