【问题标题】:Iterating over multiple parse.com classes (tables) and extracting queries遍历多个 parse.com 类(表)并提取查询
【发布时间】:2015-12-15 09:24:52
【问题描述】:

我打赌这与 Javascript 的异步性或类似的东西有关。我刚刚阅读了有关承诺的内容,并认为它可能会解决我的问题,但还没有。无论如何,这是一个代码 sn-p 以及我打算用它实现的目标:

场景:我想查询 10 个表并获取最新的帖子(为了这个示例,1 个帖子)并将其存储在格式的字典中

<Class Name> : <Obj Id>

以下代码 sn-p 执行以下操作,或尝试执行以下操作:

  1. 构建一个名为 activeTables 的数组,其中包含要查询的表列表。这个数组本身存储在一个名为 Config 的单独表中
  2. 对于数组 activeTable 的每个项目,对该项目执行查询,查找最近的项目并将其添加到字典中

看起来很简单,但这是我得到的结果:

假设我们在名为 Table_1、Table_2、Table_3 的 3 个表上运行此程序,每个表上最近的 obj 分别为:recent_1、recent_2、recent_3,我在 newlist 上看到的是:

newlist = {
   "Table_1" : ["recent_1", "recent_2", "recent_3"]
}

而不是:

newlist = {
    "Table_1" : ["recent_1"],
    "Table_2" : ["recent_2"],
    "Table_3" : ["recent_3"],
}

它打败了我,虽然我能够查询 3 个表并获得最新的帖子,但只有在将其插入字典后,一旦存在一个键,它就会拒绝为每个表添加一个新键

(另外,我是不是用错了 promises?因为我仍然看到熟悉的回调地狱金字塔)

上面引用的代码sn-p:

Parse.Cloud.job("scanLists", function(request, status) {
  var activeTables = [];
  var getclass = Parse.Object.extend("Config");
  var query = new Parse.Query(getclass);
  query.equalTo("Name", "ActiveTablesConfigObj");
  query.find().then(function(activetables_obj) {
    var newlist = {};
    activeTables = activetables_obj[0].get("cObject").Active.slice();
    for (var i = 0; i < activeTables.length; i++) {
      var t_name = activeTables[i];          
      var get_atc = Parse.Object.extend(t_name);
      var query_newlist = new Parse.Query(get_atc);
      query_newlist.descending("createdAt");
      query_newlist.find().then(function (newlist_obj) {
        if (newlist.t_name === undefined) {
          newlist[t_name] = [newlist_obj[0].id];
        } else {
          newlist[t_name].push(newlist_obj[0].id);
        }
      });
    }
  });
});

【问题讨论】:

    标签: javascript asynchronous parse-platform callback promise


    【解决方案1】:

    我们可以通过几种方式改进代码。 (1) 制作返回承诺的较小函数,(2) 当我们只想要一个结果时,使用 query.first() 而不是 find()。为了说明这两点,这里有一个函数,它返回一个获取第一个“Config”对象的承诺:

    function getConfig() {
      var query = new Parse.Query("Config");
      query.equalTo("Name", "ActiveTablesConfigObj");
      return query.first();
    }
    

    看起来,稍后在代码中,您想要获取给定类的最新对象。这是一个简洁的函数:

    function newestInstanceOf(klass) {
        var query = new Parse.Query(klass);
        query.descending("createdAt");
        return query.first();
    }
    

    这是棘手的部分(也是您的解决方案中最需要修复的部分)... query.first() 和 .find() 异步运行。您的代码包含一个 for 循环,该循环生成几个仅在函数返回后完成的承诺。不确定你的实际代码是什么样的,但这里是如何正确地做到这一点,在一个数组中收集 Promise,然后与 Promise.when() 一起执行它们:

    _ = require("underscore");  // just a great util for arrays, providing things like map()
    
    function scanLists() {
        var newlist = {};
        return getConfig().then(function(config) {
            var activeTables = config.get("cObject").Active;
            // build an array of promises to get the most recent object in each class
            var promises = _.map(activeTables, function(klass) {
                return newestInstanceOf(klass).then(function(newestInstance) {
                    if (!newlist[klass]) { newlist[klass] = []; }
                    newlist[klass].push(newestInstance.id);
                });
            });
            return Parse.Promise.when(promises);
       }).then(function() {
           return newlist;
       });
    }
    

    注意一切如何返回一个承诺?最后一件事...从云函数调用它,包括调用响应成功/错误:

    Parse.Cloud.job("scanLists", function(request, response) {
        scanLists().then(function(newlist) {
            // do something with newlist, if this involves a promise, then...
            return someObject.save();
        }).then(function(result) {
            response.success(result);
        }, function(error) {
            response.error(error);
        });
    }
    

    【讨论】:

    • 真的很喜欢读这个丹!很棒的总结和建议——对我来说还有很多东西要带走并提高代码质量
    【解决方案2】:

    解决了!

    答案是我必须使用匿名函数!

    所以下面的代码解决了这个问题

    Parse.Cloud.job("scanLists", function(request, status) {
      var activeTables = [];
      var getclass = Parse.Object.extend("Config");
      var query = new Parse.Query(getclass);
      query.equalTo("Name", "ActiveTablesConfigObj");
      query.find().then(function(activetables_obj) {
        var newlist = {};
        activeTables = activetables_obj[0].get("cObject").Active.slice();
        for (var i = 0; i < activeTables.length; i++) {
          (function(i) {
            var t_name = activeTables[i];          
            var get_atc = Parse.Object.extend(t_name);
            var query_newlist = new Parse.Query(get_atc);
            query_newlist.descending("createdAt");
            query_newlist.find().then(function (newlist_obj) {
              if (newlist.t_name === undefined) {
                newlist[t_name] = [newlist_obj[0].id];
              } else {
                newlist[t_name].push(newlist_obj[0].id);
              }
            });
          })(i);
        }
      });
    });
    

    【讨论】:

    • 很高兴你有这个工作,但我不明白它是怎么回事。代码在没有实际构建 newlist 的情况下返回(由于未处理来自 for 循环中 find() 的承诺)。此外,它必须在状态参数(通常称为“响应”)上调用 success() 或 error()。你如何收集证明它有效的证据?
    • 嗨@danh,这是我看到的关于newlist 的内容,但是如果有什么明显的错误,请告诉我,因为我还是JS 和Parse 的新手:newlist 在for 循环之前被删除.然后在 for 循环中访问它,因为如果键不存在则创建键,或者将值推送到键所属的数组中。我是我的实际代码,当我退出 for 循环时,newlist 是一个完整的字典,其中包含预期的键、值对,然后我在解析时将其写入另一个对象
    • 好的。也许它工作得比看起来更好的原因是“实际代码”中的某些东西。我会很快写下一些想法,只是为了澄清您发布的内容中的一些内容。
    猜你喜欢
    • 2015-09-03
    • 1970-01-01
    • 2016-05-18
    • 1970-01-01
    • 1970-01-01
    • 2011-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多