变量范围似乎随着jQuery异步AJAX请求而改变?

时间:2014-03-30 15:57:46

标签: jquery ajax asynchronous scope

我有一个我正在处理的项目库存跟踪系统,我似乎遇到了状态正确更新的问题。

这里是JS,从我可以告诉我在$.each循环中存在的对象的值,当ajax函数success/error/complete被用于像我注入HTML的地方。

(function() {
  function realtime() {
    // Realtime Elements...
    $('.realtime').each(function() {
      // Self Reference
      var objThis = $(this);
      // Realtime Items...
      if(objThis.hasClass('foxyinv-item')) {
        // Item Code to Check
        var valCode = objThis.find('[name=code]').val();
        // Status Element
        var objStock = objThis.find('div.stock');
        // Begin AJAX Overlap Prevention
        objThis.removeClass('realtime');
        $.ajax({
          url: 'checkstock.php',
          type: 'post',
          data: {
            session: FC.session_id,
            code: valCode,
            qty: 1
          },
          success: function(data) {
            var response = data.split(':');
            switch(response[0]) {
              case 'ok':
                console.log(valCode+' can be sold, it is '+response[1]);
                objStock.html(valCode+'<button type="submit">Add to Cart</button>'+response[1]);
                break;
              case 'no':
                console.log(valCode+' cannot be sold, it is '+response[1]);
                objStock.html(response[1]);
                break;
              default:
                objStock.html('<span class="error">Error!</span>');
                break;
            }
          },
          error: function() {
            console.log('checkstock.php error!');
            objStock.html('<span class="error">Error!</span>');
          },
          complete: function() {
            // End AJAX Overlap Prevention
            objThis.addClass('realtime');
          }
        }); // $.ajax()
      }
    }); // $('.realtime').each()
  } // realtime()

  // Document Ready...
  $(document).on('ready', function() {
    // Main Loop...
    var RTI = setInterval(function() { realtime() }, 5000);
    realtime();
  });
})();

这是显示产品的页面上的代码片段

// Items
$items = '';
$result = mysqli_query($mysqli, "SELECT * FROM foxyinv_items");
if($result && mysqli_num_rows($result) > 0) {
  while($assoc = mysqli_fetch_assoc($result)) {
    $items .=
      '<div class="foxyinv-item realtime">'.
        '<form action="https://mlkart.foxycart.com/cart" method="post" accept-charset="utf-8">'.
          '<input type="hidden" name="name" value="'.$assoc['item_name'].'" />'.
          '<input type="hidden" name="code" value="'.$assoc['item_code'].'" />'.
          '<input type="hidden" name="price" value="'.$assoc['item_price'].'" />'.
          '<div class="name">'.$assoc['item_name'].'</div>'.
          '<div class="code">'.$assoc['item_code'].'</div>'.
          '<div class="price">'.$assoc['item_price'].'</div>'.
          '<div class="stock">Checking...</stock>'.
        '</form>'.
      '</div>';
  }
  mysqli_free_result($result);
}

回调脚本运行正常,但例如它将返回这些类型的响应:

ok:(可以添加,无状态)

ok:In Stock(可以添加状态)

no:Out of Stock(无法添加状态)

error(mgmt面板中存在错误)

最简单的问题是,如何确保javascript变量objThisvalCodeobjStock与ajax调用时保持一致制作?我将研究同步进行ajax调用的可能性,但我不喜欢它会在调用完成之前挂起页面的含义,因此同步调用不是可接受的解决方案。

修改

使用jfriend并按照建议评论所有内容,控制台指示范围正在维护,但是当引用.html(code)时,它将被发送到错误的对象。这是控制台日志:

1: start
1: inside hasClass'foxyinv-item'
1: about to call ajax, valCode=EX-02
1: objThis.data(code)=EX-02
1: success: valCode=EX-02
1: success: data=ok:In Stock
1: EX-02 can be sold, it is In Stock
1: objThis.data(code)=EX-02
1: ajax complete
1: objThis.data(code)=EX-02 
2: start
2: inside hasClass'foxyinv-item'
2: about to call ajax, valCode=EX-01
2: objThis.data(code)=EX-01
2: success: valCode=EX-01
2: success: data=error
2: EX-01 cannot be sold, it has an error!
2: objThis.data(code)=EX-01
2: ajax complete
2: objThis.data(code)=EX-01

这变得越来越奇怪了......


解决方案: 好吧,所以我觉得自己像一个完全白痴,我很惊讶没有人接受它...在我的项目显示脚本中我非常巧妙地使用'<div class="stock">Checking...</stock>'。我修好了它,实际上是</div>

很抱歉浪费了你这么多时间的朋友。然而,你确实让我开始了正确的道路,因为我发现范围正在维持,它必须在另一个涉及的文件中。我希望我能早点接受它!深夜和清晨正在迎头赶上!

1 个答案:

答案 0 :(得分:0)

.each()回调中的任何变量的值(如objThisvalCodeobjStock都在闭包中,并且会为每个单独的ajax回调函数保留其值。这是使用带有回调函数的.each()与使用没有内置闭包的for循环的优点之一。

现在,如果在ajax调用完成之前随时修改了这些变量所指向的基础数据,那么你仍然会遇到问题,解决这个问题的唯一方法就是停止修改你不知道的数据。我想更改或制作该数据的本地副本,以免任何人弄乱您的副本(在这种情况下,这看起来不像是一个问题)。


为了追踪究竟发生了什么,我建议如下:

在全球范围内声明:

var transactionId = 0;

然后,使用console.log()这样的语句检测代码:

(function() {
  function realtime() {
    // Realtime Elements...
    $('.realtime').each(function() {
      var localId = ++transactionId;
      console.log(localId + ": start");
      // Self Reference
      var objThis = $(this);
      // Realtime Items...
      if(objThis.hasClass('foxyinv-item')) {
        console.log(localId + ": inside hasClass'foxyinv-item'");
        // Item Code to Check
        var valCode = objThis.find('[name=code]').val();
        // Status Element
        var objStock = objThis.find('div.stock');
        // Begin AJAX Overlap Prevention
        objThis.removeClass('realtime');
        console.log(localId + ": about to call Ajax, valCode=" + valCode);
        $.ajax({
          url: 'checkstock.php',
          type: 'post',
          data: {
            session: FC.session_id,
            code: valCode,
            qty: 1
          },
          success: function(data) {
            console.log(localId + ": success: valCode=" + valCode);
            console.log(localId + ": success: data=" + data);
            var response = data.split(':');
            console.log(localId + ": success: response=" + response);
            switch(response[0]) {
              case 'ok':
                console.log(valCode+' can be sold, it is '+response[1]);
                objStock.html(valCode+'<button type="submit">Add to Cart</button>'+response[1]);
                break;
              case 'no':
                console.log(valCode+' cannot be sold, it is '+response[1]);
                objStock.html(response[1]);
                break;
              default:
                objStock.html('<span class="error">Error!</span>');
                break;
            }
          },
          error: function() {
            console.log(localId + ": ajax error");
            console.log('checkstock.php error!');
            objStock.html('<span class="error">Error!</span>');
          },
          complete: function() {
            console.log(localId + ": ajax complete");
            // End AJAX Overlap Prevention
            objThis.addClass('realtime');
          }
        }); // $.ajax()
      }
    }); // $('.realtime').each()
  } // realtime()

  // Document Ready...
  $(document).on('ready', function() {
    // Main Loop...
    var RTI = setInterval(function() { realtime() }, 5000);
    realtime();
  });
})();

注意:正如您已经猜测的那样,您不应该切换到同步ajax。这不是编码或解决您可能遇到的任何问题的正确方法。