原子'读 - 修改 - 写'在javascript中

时间:2015-09-23 21:57:13

标签: javascript parse-platform promise

我正在开发一个在线商店应用程序,并使用Parse作为后端。我商店中每件商品的数量有限。以下是我processOrder函数执行操作的高级描述:

  1. 找到用户想要从数据库中购买的商品
  2. 检查每个项目的剩余计数是否足够
  3. 如果步骤2成功,则更新剩余计数
  4. 检查剩余计数是否为负数,如果是,则将剩余计数还原为旧值
  5. 理想情况下,上述步骤应该专门执行。我了解到Javascript是一个单线程和基于事件的,所以这是我的问题:

    1. Javascript中没有办法将上述步骤放在关键部分,对吗?
    2. 假设只剩下3个项目,两个用户分别尝试订购其中的2个。对于其中一个用户,剩余计数将最终为-1,因此在这种情况下,剩余计数需要恢复为1。想象一下,当剩余计数为-1时,另一个用户试图订购1个项目,尽管他应该被允许订购,但他将失败。我该如何解决这个问题?
    3. 以下是我的代码:

      Parse.Cloud.define("processOrder", function(request, response) {
          Parse.Cloud.useMasterKey();
      
          var orderDetails = {'apple':2, 'pear':3};
      
          var query = new Parse.Query("Product");
      
          query.containedIn("name", ['apple', 'pear']);
      
          query.find().then(function(results) {
                  // check if any dish is out of stock or not
                  _.each(results, function(item) {
                          var remaining = item.get("remaining");
                          var required = orderDetails[item.get("name")];
      
                          if (remaining < required)
                                  return Parse.Promise.error(name + " is out of stock");
                  });
      
                  return results;
          }).then(function(results) {
                  // make sure the remaining count does not become negative   
                  var promises = [];
      
                  _.each(results, function(item) {
                          item.increment("remaining", -orderDetails[item.get("name")]);
                          var single_promise = item.save().then(function(savedItem) {
                                  if (savedItem.get("remaining") < 0) {
                                          savedItem.increment("remaining", orderDetails[savedItem.get("name")]);
                                          return savedItem.save().then(function(revertedItem) {
                                                  return Parse.Promise.error(savedItem.get("name") + " is out of stock");
                                          }, function(error){
                                                  return Parse.Promise.error("Failed to revert order");
                                          });     
                                  }
                          }, function(error) {
                                  return Parse.Promise.error("Failed to update database");
                          });
                          promises.push(single_promise);
                  });
                  return Parse.Promise.when(promises);
      
          }).then(function() {
                  // order placed successfully
                  response.success();
      
          }, function(error) {
                  response.error(error);
          });
      

      });

1 个答案:

答案 0 :(得分:0)

  

在Javascript中无法将上述步骤放在关键部分,对吗?

看,这是令人惊讶的部分。在JavaScript 中,所有内容都在关键部分中运行。没有先发制人和多处理是合作的。如果您的代码开始运行,那么在您的代码完成之前,其他任何代码都无法运行。

即使您的代码已完成执行。

问题是,你正在做IO,而JavaScript中的IO会在实际发生类似阻塞代码之前产生回事件循环。因此,当您创建并运行查询时,您实际上并不会立即继续运行(这就是您的回调/承诺代码的内容)。

  

理想情况下,上述步骤应该专门执行。

可悲的是,这不是一个JavaScript问题,在这种情况下,这是一个主机环境问题Parse。这是因为当你使用他们的API(通过回调和承诺)时,你必须明确地控制其他代码,并由他们来解决它。

幸运的是,parse has atomic counters。来自API文档:

  

为了帮助存储计数器类型数据,Parse提供了以原子方式递增(或递减)任何数字字段的方法。因此,相同的更新可以重写为。

gameScore.increment("score");
gameScore.save();

您还可以使用原子数组操作。由于您可以原子地执行步骤3,因此可以保证计数器代表实际库存。