嗨我有一个问题,我正在尝试迭代一个键列表,创建一个匹配实体列表 代码看起来像这样
let previous = undefined;
for (let i = offset; i < response.keys.length; i++) {
logger.debug("iteration " + i + " previous: " + previous)
logger.debug("instance key: " + response.keys[i])
if (previous) {
previous = previous
.then((entities) => {
if (entities.length === limit) {
i = response.keys.length;
} else {
readEntity(response.keys[i])
.then((instance) => {
matchInstance(instance, conditions)
logger.debug("is match: " + isMatch)
.then((isMatch) => {
if (isMatch)
entities.push(instance);
//resolve(entities);
}).catch((err) => {
reject(err)
})
}).catch((err) => {
reject(err)
})
}
}).catch((err) => {
reject(err)
})
} else {
previous = readEntity(response.keys[i])
.then((instance) => {
logger.debug("reading instance: " + instance.key)
matchInstance(instance, conditions)
.then((isMatch) => {
if (isMatch) {
return instance
} else {
logger.debug("instance does not match")
}
}).catch((err) => {
reject(err)
})
}).catch((err) => {
reject(err)
})
}
}
但它只通过for循环一次,就像,它没有返回任何东西?
我也有一些调试
2017-10-04T15:09:58+0200 <debug> data.js:202 (seekKeys.then) iteration 0 previous: undefined
2017-10-04T15:09:58+0200 <debug> data.js:203 (seekKeys.then) instance key: employees/existing@...
2017-10-04T15:09:58+0200 <debug> data.js:202 (seekKeys.then) iteration 1 previous: [object Promise]
2017-10-04T15:09:58+0200 <debug> data.js:203 (seekKeys.then) instance key: employees/test@...
2017-10-04T15:09:58+0200 <debug> data.js:202 (seekKeys.then) iteration 2 previous: [object Promise]
2017-10-04T15:09:58+0200 <debug> data.js:203 (seekKeys.then) instance key: employees/unique@...
2017-10-04T15:09:58+0200 <debug> data.js:202 (seekKeys.then) iteration 3 previous: [object Promise]
2017-10-04T15:09:58+0200 <debug> data.js:203 (seekKeys.then) instance key: employees/update@...
2017-10-04T15:09:59+0200 <debug> data.js:231 (readEntity.then) reading instance: existing@...
2017-10-04T15:09:59+0200 <debug> data.js:237 (matchInstance.then) instance does not match
如果您需要更多信息,请告诉我。谢谢
答案 0 :(得分:1)
下一次,如果不是只是在一个问题中转储一堆代码,那么你会更容易提供帮助,你实际上已经解释了你想要用语言完成的内容(以及代码)。我试图对代码的目标进行逆向工程,这就是我认为你想要做的事情:
response.keys
。limit
个匹配项,并在limit
个匹配后停止查找更多匹配项。response.keys
中的项目顺序查找这些匹配项。readEntity(val).then()
检测匹配,然后进行matchInstance().then()
测试。limit
。以下是三个单独的设计模式,用于序列化数组的迭代,您在每个数组元素上执行异步操作,并希望一个接一个地(不是并行)执行它们。在收集limit
结果后,要求停止处理,使您的特定情况稍微复杂一些。
.reduce()承诺链接
用于序列化基于承诺的异步操作的经典设计模式是使用.reduce()
,其中减少中的累加器值是一个承诺,并链接到该承诺以强制序列化。您可以这样实现:
// get subset of response.keys that we can process with .reduce()
let keys = response.keys.slice(offset);
keys.reduce((p, val) => {
// return promise so we continually chain
return p.then(entities => {
// if entities is not yet full
if (entities.length < limit) {
return readEntity(val).then(instance => {
return matchInstance(instance, conditions).then(isMatch => {
if (isMatch) {
entities.push(instance);
}
// resolved value is entities so that is passed down the chain
return entities;
});
});
} else {
return entities;
}
});
}, Promise.resolve([])).then(entities => {
// process results here
}).catch(err => {
// process error here
});
示例实施:https://jsfiddle.net/jfriend00/uspa8vgd/
在此承诺链中,promise的已解析值是结果数组。它被初始化为一个空数组,其中Promise.resolve([])
作为初始累加器值传递给.reduce()
,然后.reduce()
回调的结算值总是相同entities
阵列。通过这种方式,它会在链中传递,链中的每个链接都有机会添加(或不基于isMatch
测试)。
手动迭代并使用next()函数链接
这是另一种按顺序迭代的设计模式。我创建了一个通常称为next()
的内部函数。该函数要么返回一个promise或一个值。如果它返回一个值,则迭代完成。如果它返回一个promise,则迭代继续,每次迭代链接到前一个迭代。最终解析的值是您在迭代期间累积的任何值。在这里它是entities
数组。
function runMatchIteration(data, offset, limit) {
let i = offset;
let entities = [];
function next() {
if (i < data.length && entities.length < limit) {
return readEntity(data[i++]).then(instance => {
return matchInstance(instance, conditions).then(isMatch => {
if (isMatch) {
entities.push(instance);
}
// now execute next cycle - chaining onto original promise
return next();
});
});
} else {
// done with loop here
return entities;
}
}
return Promise.resolve().then(next);
}
// usage
runMatchIteration(response.keys, offset, limit).then(entities => {
// process results here
}).catch(err => {
// process error here
});
示例实施:https://jsfiddle.net/jfriend00/t5bmzkb6/
使用Bluebird的Promise.mapSeries()在系列中运行
Bluebird promise library有许多有用的功能来管理和排序承诺。其中包括Promise.mapSeries()
,它将数组作为输入并序列化调用数组中每个项的函数。因为你要求在limit
结果之后停止,我们必须使用它与平时略有不同,但它仍然使代码相当简单:
let entities = [];
Promise.mapSeries(response.keys.slice(offset), item => {
if (entities.length < limit) {
return readEntity(item).then(instance => {
return matchInstance(instance, conditions).then(isMatch => {
if (isMatch) {
entities.push(instance);
}
});
});
}
}).then(() => {
// process entities result here
}).catch(err => {
// handle error here
});
对原始代码的一些观察:
.then()
处理程序中运行新的异步操作时,必须从.then()
回调中返回这些promise,以便它们链接到父承诺。否则,您将创建各种独立的未链接的承诺链,并且您永远不知道何时完成任何事情并且无法协调不同的承诺链。for
循环索引。 for
循环是同步的,并且在任何异步回调执行之前已经完成了很长时间。因此,每当您尝试操作其索引时,for
循环就已完成。答案 1 :(得分:0)
您可以为此(不推荐):
编写递归函数let index = 0;
let errors = [];
function promiseIterator (index) {
if (response.keys[index]) {
readEntity(response.keys[index]).then((instance) => {
matchInstance(instance, conditions).then(() => {
logger.debug("is match: " + isMatch).then(() => {
if (isMatch) entities.push(instance);
promiseIterator(index+1);
});
});
}).catch((err) => {
//error handler
errors.push({keyIndex: index, err: err});
promiseIterator(index+1);
});
}
}
promiseIterator(offset);
// do your stuff with error array
上述代码可能不准确,请根据您的要求进行调整。
但是,由于您需要对承诺进行迭代,因此建议使用bluebird
库并实施each
或all
功能取决于您的要求。