【问题标题】:Javascript: Save AJAX Result in as Class variableJavascript:将 AJAX 结果保存为类变量
【发布时间】:2016-06-29 10:35:27
【问题描述】:

我知道 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

【问题讨论】:

  • 有多种方法可以解决这个问题,这取决于您需要的行为究竟是什么
  • 您可以为 AJAX 调用中的错误设置 data = undefined 或创建一些错误标志。因此,无论何时数据未定义或您有错误标志 - 您都知道您的 AJAX 调用是否成功。
  • 你可以使用$.extend函数对所有函数进行margin并添加不同的属性
  • 我怀疑Ajax.success(function(data){this.data = data;}); 中的this 是否有效。最好使用箭头函数,self = this;bind(this);

标签: javascript jquery ajax callback


【解决方案1】:

您可以使用$.ajax()context设置在$.ajax()回调,deferred.then()处设置this;在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)
})

【讨论】:

    【解决方案2】:

    我为此开发了自己的 jQuery ajax 包装器,但它确实需要 jQuery...如果这有助于检查我的 github 存储库

    JQPS Framework v. 1.1b - Github

    这对您有很大帮助,它通过命名空间(您正在寻找的类)使用 OOP,例如 Myobject.vars.anything = value(来自回调)

    调用示例

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

    这将触发对http://yoursite.com/auth/login 的ajax 调用,其中dataObj 作为post 对象,在回调中第一个函数将被调用,在我们的例子中是Utils.setVar(),这会将来自回调的响应存储在@ 987654326@,正如我们在回调对象中定义的那样,之后第二个函数将被触发并按照调用Utils.anyOtherFunction()中定义的方式执行......你可以在回调中添加你想要的函数。

    有关更多信息,您可以查看 github 的自述文件,这是为同步和异步调用设置的,但它确实需要 jQuery,没有它就无法工作。

    【讨论】:

      【解决方案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】:

        为了将返回数据保存在所谓的Class 变量中,在您的示例中,您需要了解使用this 关键字的上下文。 在你的例子中

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

        this 引用 Ajax 对象。

        由于 Reader 对象中的 this.data 几乎封装在 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;
            }
        

        【讨论】:

          【解决方案5】:

          使用全局 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
          }
          

          【讨论】:

          • 全局变量不好,尤其是当它们被同一个类的多个实例访问时。
          • 真的吗?它只是扩大范围。这类似于任何其他对象变量或函数变量
          • 不要相信我的话,但请阅读:stackoverflow.com/questions/10525582/…
          • @dburner 不。我不同意。这取决于您使用全局变量的方式和频率。这个要求只需要一个全局变量就可以了。
          【解决方案6】:

          人们痴迷于使用原型在类中创建函数,但有一种更简洁的方法,即使用带有“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);
          

          正常。

          【讨论】:

            【解决方案7】:

            一个简单的解决方案是将所有函数调用放在另一个函数中,并且只从回调中调用那个函数:

            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
            
            };
            

            【讨论】:

              【解决方案8】:

              您的问题是关于“this”键的混淆。

              当您在函数中使用 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;
                 });
              }
              

              这就是你的问题的解决方案。

              【讨论】:

                【解决方案9】:

                尝试改变这一点:

                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;
                   });
                }
                

                【讨论】:

                  【解决方案10】:

                  最重要的部分是如何使用 JavaScript 处理异步数据。对此有一些经过充分测试的解决方案:函数和承诺。

                  在这两种情况下,Reader 都应该有一个构造函数,它可以像这样分配数据:

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

                  回调方法需要一个工厂函数,它有一个回调。

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

                  并像使用它

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

                  Promise 方法不需要立即回调,因此可以将结果存储在变量中并作为变量传递,这有一些优势:

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

                  但是,使用 Promise 通常需要调用 Promise 的 then 函数:

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

                  将来你可以使用 ES6 生成器来摆脱带有 Promise 的回调,比如

                  let reader = yield getReaderPromise( url );
                  

                  如此处所述:https://davidwalsh.name/async-generators

                  【讨论】:

                    【解决方案11】:

                    你可以试试这样的:

                    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(...);
                       }
                    }
                    

                    【讨论】:

                      【解决方案12】:

                      这是我认为解决它的好方法,不过它需要几个回调

                      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
                      }
                      

                      【讨论】:

                        【解决方案13】:

                        你可以这样做

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

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 2016-05-20
                          • 1970-01-01
                          • 1970-01-01
                          • 2014-05-25
                          • 1970-01-01
                          • 2016-04-18
                          • 1970-01-01
                          相关资源
                          最近更新 更多