我不是一个承诺忍者,我明白我做错了什么。但是,我无法找到一些特定/类似的问题。
问题:我使用异步的IndexedDB的Dexie.js包装器。我有一个全球数据库,可以通往其他一些dexie数据库。
function handleDatabases() {
var result = [];
db.jobs.orderBy('title').filter(function(job) {
return job.someBooleanCondition;
}).each(function(job, cursor) {
let jobDetails = new Dexie(job.correspondingDB);
jobDetails.version(1).stores({
details: 'key,value1,value2'
});
jobDetails.details.get(someKey).then(function(detail) {
result.push({job: job, detail: detail});
})
}).catch(function(error) {
console.log(error);
});
handleResult(result);
}
我已经用一种奇怪的形式重写了它,但最终目标是我可以使用数组result
来处理一些更新。但是,由于它是异步的,所以它总是为空的,直到你在控制台中检查它永远不会为空。如何将其重写为同步?
答案 0 :(得分:4)
当结果仅异步可用时,您不能期望返回结果。
所以你必须一直坚持承诺(每次都返回),让你的函数也返回一个承诺。调用者必须使用then
(如果支持,则为await
)以允许(异步)访问结果。
不是将{job: job, detail: detail}
推送到结果变量,而是将其返回。它将成为jobDetails.details.get(..).then(..)
的承诺价值。如果你还返回,那么你将拥有一系列的承诺,然后可以使用Promise.all
来解决这个承诺
避免创建新的Promise,因为这通常会导致promise constructor antipattern。
同时避免使用在多个回调中使用的变量(如结果)而不作为参数传递。而是尝试构造并将该数组作为承诺值返回,因此可以在下一个then
回调中使用它。
以下是建议的(未经测试的)代码:
function handleDatabases() {
db.jobs
.orderBy('title')
.filter(job => job.someBooleanCondition)
.toArray(jobs =>
jobs.map(job => {
let jobDetails = new Dexie(job.correspondingDB);
jobDetails.version(1).stores({
details: 'key,value1,value2'
});
return jobDetails.details.get(someKey)
.then(detail => ({job: job, detail: detail}))
}) // is returned
)
.then(result => Promise.all(result))
.then(handleResult)
.catch(error => console.log(error));
}