Im betting this has something to do with asynchronicity of Javascript or something like that. I just read up about promises and thought it might solve my issue, but it hasnt yet. Anyhow, here is a code snippet and what Im aiming to achieve with it:
The scenario: I would like to query 10 tables and get the most recent posts(for sake of this example, 1 post) and store that in a dictionary of format
<Class Name> : <Obj Id>
The below code snippet does the following, or tries to do the following:
Seems straightforward but here's the result Im getting:
Assuming we run this on 3 tables called Table_1, Table_2, Table_3 and the most recent objs on each table are: recent_1, recent_2, recent_3 respectively, what I see on newlist is this:
newlist = {
"Table_1" : ["recent_1", "recent_2", "recent_3"]
}
instead of :
newlist = {
"Table_1" : ["recent_1"],
"Table_2" : ["recent_2"],
"Table_3" : ["recent_3"],
}
and it beats me, that while I was able to query the 3 tables and get the most recent post, only upon inserting it into the dictionary, it refuses to add a new key per table, once one key exists
(Also, am I using promises wrong? Since i still see the familiar pyramid of callback hell )
Code snippet referenced above:
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);
}
});
}
});
});
答案 0 :(得分:0)
解决!
答案是我必须使用匿名函数!
以下代码修复了问题
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);
}
});
});
答案 1 :(得分:0)
我们可以通过几种方式改进代码。 (1)创建返回promises的较小函数,(2)当我们只需要一个结果时,使用query.first()而不是find()。为了说明这两点,这里有一个函数,它返回一个承诺,以获得第一个&#34; Config&#34;对象:
function getConfig() {
var query = new Parse.Query("Config");
query.equalTo("Name", "ActiveTablesConfigObj");
return query.first();
}
看起来,稍后在代码中,您希望获得给定类的最新对象。继承人&#39;一个简洁的功能:
function newestInstanceOf(klass) {
var query = new Parse.Query(klass);
query.descending("createdAt");
return query.first();
}
这里是棘手的部分(以及需要在解决方案中修复的部分)... query.first()和.find()异步运行。您的代码包含一个for循环,它生成几个只在函数返回后才能完成的promise。不确定你的实际代码是什么样的,但是这里是如何正确地完成它,在数组中收集promises,然后与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);
});
}