我在解决这个逻辑问题时遇到了问题,我甚至不知道它是否可行,或者我是否在这里正确使用了承诺。
我有第一个函数,它接收一个ID列表,用于发出请求以提取特定的异步数据。我一次只能输入1000,所以如果列表中包含超过1000个,我必须通过它进行递归。
我正在寻找的是 - 对于您需要递归的每个选项,请调用递归函数,等待结果,然后将它们推送到列表中。获得所有数据后,请回复数据。
async function getData () {
....
// Inside condition that determines it needs to recurse
let _data = await _getOptions(id, data, 0);
dataList.push(_data);
...
// Eventually, return the data
res.json(dataList);
}
此函数通过列表进行递归,并且一旦所有数据被拉入,就应该解析。
let rData = [];
function _getOptions(id, data, offset) {
return new Promise((resolve, reject) => {
if (data.length < 1000) {
return resolve(rData);
}
let fields = { fields: `id, key_value, label, condition_value`, offset: offset, limit: 1000 };
options.getOptionsWithFilter(id, fields, (err, data) => {
rData.push(data);
_getOptions(id, data, offset + 1000);
});
});
}
由于控制台中出现错误,这似乎不起作用,这表明它会返回undefined
。我猜这个问题是我在这里使用了错误的承诺。但我一直在努力想出另一个解决方案。在我继续前进之前,我需要在_data
变量中返回所有数据。
答案 0 :(得分:5)
你的promise构造函数回调应该总是调用resolve
(或reject
),但是当你继续进行递归调用时,你不会调用resolve
在那个特定的承诺上。所以称之为:
resolve(_getOptions(id, data, offset + 1000));
我还认为组合结果数据块的方法是错误的:您可以将数组作为嵌套数组推送到最终数组中。我希望你需要将这些块连接成一维数组。
使用data
变量时出现问题:您将其用于传递给_getOptions
函数的内容(不确定最初是什么),还用于 getOptionsWithFilter
提供。我认为后面的数据实际上是你正在处理的唯一data
。因此,您无需将其传递给_getOptions
。
建议避免使用全局rData
变量。由于您只将其设置为空数组一次,因此您可能无法为要进行的任何下一个请求清除它。
相反,让最终的承诺产生最后的数据块,然后将之前的块预先添加到它:
function _getOptions(id, offset = 0) { // No data argument!
return new Promise((resolve, reject) => {
let fields = { fields: `id, key_value, label, condition_value`,
offset: offset, limit: 1000 };
options.getOptionsWithFilter(id, fields, (err, data) => {
if (data.length < 1000) { // Perform the check when you have the data
return resolve(data); // just this chunk
}
resolve(_getOptions(id, offset + 1000) // Don't pass data
// prepend this data to the data that the recursive
// promise will provide
.then(rData => data.concat(rData))
);
});
});
}
你这样称呼它:
_data = await _getOptions(id);
你也可以选择在一个Promise构造函数回调中执行异步循环(“递归调用”):
function _getOptions(id) { // No data argument!
return new Promise((resolve, reject) => {
let rData = [];
(function loop(offset) {
let fields = { fields: `id, key_value, label, condition_value`,
offset: offset, limit: 1000 };
options.getOptionsWithFilter(id, fields, (err, data) => {
rData = rData.concat(data);
if (data.length < 1000) { // Perform the check when you have the data
return resolve(rData); // All retrieved data
}
loop(offset + 1000); // Collect more
});
})(0); // Call immediately
});
}