添加了异步行为,无法使代码适合它

时间:2013-01-28 12:56:37

标签: javascript jquery ajax

在我以前使用

之前
//get state
   MyClass.prototype.getState = function(key) {
       var value;
       switch(this._options.type){
          case "cookie":
                value = $.cookie(key);
                break;

          case "localStorage":
                value = window.localStorage.getItem(key);
                break;
        }

        this._options.afterGetState(key, value);
        return value;
    };

   //set state
   MyClass.prototype.setState = function(key, value) {
        switch(this._options.type){
          case "cookie":
                $.cookie(key, value); 
                break;

          case "localStorage":
                window.localStorage.setItem(key, value));
                break;
        }
        return this._options.afterSetState(key, value);
      };



    MyClass.prototype.ended = function() {
        return !!this.getState("is_ended");
      };

    MyClass.prototype.setStep = function(value) {
        if (value != null) {
          this._current = value;
          return this.setState("step", value);
        } else {
          this._current = this.getState("step");
          if (this._current === null || this._current === "null") {
            return this._current = 0;
          } else {
            return this._current = parseInt(this._current);
          }
        }
      };

      MyClass.prototype.end = function() {
        this.setState("end", "true");
      };

已经使用了localStorage和cookie。现在我添加了在db中存储数据的功能,因此我必须使用ajax和async函数。所以我改变了代码:

//get state async
   MyClass.prototype.getState = function(key, callback) {
        oldThis = this;
        //h-mmm... what if callback is null or undefined? Will it work for function(){ }?
        callback = typeof callback != 'undefined' ? callback : function(){ }
        switch(this._options.storageType){

          case "cookie":
            setTimeout(function(){ 
                    value = callback($.cookie(key)); 
                    oldThis._options.afterGetState(key, value);
                    return value;
                  },
              0);
            break;

          case "localStorage":
            setTimeout(function(){ 
                  callback(window.localStorage.getItem(key));
                  oldThis._options.afterGetState(key, value);
                  return value;
                },
              0);
            break;

          case "db":
            $.ajax({
                type: "GET",
                url: "/123",
                data: { .... },
                success: function(data){
                  value = callback(data);
                  oldThis._options.afterGetState(key, value);
                  return value;
                },
                error: function() {
                  alert('Error occured');
                  return undefined;
                }
            });
            break;
        }
      };

  //set state async
  MyClass.prototype.setState = function(key, value, callback) {
        oldThis = this;
        callback  = callback || function(){ }
        switch(this._options.storageType){
          case "cookie":
                setTimeout(function(){ 
                        callback($.cookie(key, value)); 
                        return oldThis._options.afterSetState(key, value);
                     },
                0);
                break;

          case "localStorage":
                setTimeout(function(){ 
                      callback(window.localStorage.setItem(key, value));
                      return oldThis._options.afterSetState(key, value);
                    },
                0);
                break;

          case "database":
                $.ajax({
                    type: "POST",
                    url: "123",
                    data: { .... },
                    success: function(data){
                      callback(data);
                      return oldThis._options.afterSetState(key, value);
                    },
                    error: function() {
                        alert('Error occured');
                    }
                });
            break;
        }
      };

那么如何更改prototype.ended,prototype.setStep和prototype.end函数呢?这是我做的:

//nothing has been changed. Is this correct? It seems to be so.
MyClass.prototype.ended = function() {
    return !!this.getState("end");
  };

MyClass.prototype.setStep = function(value) {
    if (value != null) {
      this._current = value;
      return this.setState("step", value, function(value){ return value; });
    } else {
        oldThis = this;
        this.getState("step", function(value){ oldThis._current = value; });
      if (this._current === null || this._current === "null") {
        return this._current = 0;
      } else {
        return this._current = parseInt(this._current);
      }
    }
  };

//nothing has been changed. Is this correct as well?
  MyClass.prototype.end = function() {
    this.setState("end", "true");
  };

最重要的是,我无法确定应该从以下位置返回值:来自prototype.setState and prototype.getState还是来自prototype.end, prototype.enden and prototype.setStep

1 个答案:

答案 0 :(得分:1)

在处理异步操作时,必须使用回调函数而不是return语句。

例如,这个同步代码:

function syncFunc() {
    return 10;
}
var val = syncFunc();
doSomethingWithVal(val);

当函数是异步时,应该变成这样的东西:

function asyncFunc(callback) {
    setTimeout(function() {
       var data = 10;
       // Call the callback when async op is finished
       callback(data);
    }, 1000);
}
asyncFunc(doSomethingWithVal);

就您的特定代码而言,这意味着这不起作用:

MyClass.prototype.ended = function() {
    return !!this.getState("end");
};

您无法从ended返回(它可能始终返回undefined,因为getState将在回调之前返回)。你不能再使用像var x = obj.ended()这样的东西了,你必须重新考虑你的逻辑。对于setStep也是如此,你不能只返回getState的返回值,因为它现在是异步的。