我有一个for循环,在这个循环中,我迭代了一组来自json的大约50个对象。在每次迭代中,我都创建一个对象并将其推入数组中。我的意图是,在for循环结束之后,我的数组也完成了,现在我想把这个数组作为对象的一部分推入一个猫鼬集合中。
当然,问题是,当以同步方式编写它时,我会将一个空数组推送到Mongo,因为它不会等待循环结束。现在,我以前做的是一些丑陋的事情。我等待for循环中的我成为array.length -1,然后将推送处理到DB部分。这里的问题是,由于JS的异步特性,它不能保证获得迭代array.length -1可以在JS-3之前运行的所有结果,但我并不介意返回。
现在,我需要数组中的所有迭代。
fetch("https://api.com/something/"
.then(r => r.json())
.then(data => {
let arrayToFill = [];
for (let i = 0; i < data.length; i++) {
let objectToFillTheArrayWith;
objectData = data[i];
// Inside the for loop I make an async call to my DB for info
Game.findOne({ "address": objectData.address })
.then(existingGame => {
if (!existingGame) {
objectToFillTheArrayWith = {
title: objectData.name,
description: objectData.description,
image: objectData.featured_image_url,
price: objectData.stats.market_cap
}
arrayToFill.push(objectToFillTheArrayWith);
}
})
.catch(err => {
next(err)
});
}
let searchObjectDocument = {
name: "Games",
results: arrayToFill
}
// As you can understand, right now the results key value is an empty array
new SearchObject(searchObjectDocument).save();
// ...
有一个已知的,直观的解决方案吗?有些事情并不像等待我成为array.length -1,甚至可能启动一个计数器,直到计数器与数组的长度-1相同,以此类推。
谢谢
发布于 2018-12-31 18:46:29
这个问题的关键,以及所有这些关于S.O.的问题,都是看森林而不是看树。从高层开始,你真正需要的是:
fetch("https://api.com/something/")
.then(r => r.json())
.then(data => {
// convert data into a list of games
}).then(games => {
let searchObjectDocument = {
name: "Games",
results: games
}
return new SearchObject(searchObjectDocument).save();
}).then( // ...
现在您可以看到如何执行,您可以填补空白-如何将一个数组的“数据”对象转换成一个数组的查询结果?希望您使用的是蓝鸟,在这种情况下,Promise.map
是最简单的方法:
fetch("https://api.com/something/")
.then(r => r.json())
.then(data => {
return Promise.map(data, row => {
return Game.findOne({ "address": row.address })
.then(existingGame => {
if (!existingGame) {
return {
title: row.name,
description: row.description,
image: row.featured_image_url,
price: row.stats.market_cap
};
}
});
});
}).then(games => {
// At this point "games" is an array, but some entries
// are undefined (the ones where gameExisted already).
games = games.filter(game => game);
let searchObjectDocument = {
name: "Games",
results: games
}
return new SearchObject(searchObjectDocument).save();
}).then( // ...
请注意,如果有50个传入游戏,您将向您的数据库发出50个并发请求。这可能很好,但一般来说,您希望确保您正在使用的客户端具有内置节流阀,或者自己添加一个节流阀。(蓝鸟提供了一个易于使用的并发选项,用于需要自己动手的情况。)
发布于 2018-12-31 18:38:43
您最好的选择是使用异步库。很简单也很受欢迎的图书馆。
这是一个如何使用它的例子。
const async = require('async')
fetch("https://api.com/something/"
.then(r => r.json())
.then(data => {
let arrayToFill = [];
async.forEach(data, function(item, callback){
let objectToFillTheArrayWith;
Game.findOne({ "address": item.address })
.then(existingGame => {
if (!existingGame) {
objectToFillTheArrayWith = {
title: item.name,
description: item.description,
image: item.featured_image_url,
price: item.stats.market_cap
}
arrayToFill.push(objectToFillTheArrayWith);
}
// When the async is completed you should call callback where the first parameter is an error
callback(null)
})
.catch(err => {
// In case of an error callback with error
callback(err)
});
}, function(err){
// Your loop have completed
if(err) {
// The loop completed with an error, handle your error
} else {
// Your loop was completed successfully
let searchObjectDocument = {
name: "Games",
results: arrayToFill
}
// As you can understand, right now the results key value is an empty array
new SearchObject(searchObjectDocument).save();
// ...
}
})
异步是一个很好的库,学习它不会有任何伤害,实际上它将是非常有益的。
如果你真的不想使用第三方库,那么你的下一个赌注就是创建承诺数组。
每次您进入循环而不是执行Game.findOne()...
时,您都会执行一系列承诺。
类似于这个(记住这不是完整的代码,它只是一个例子)
var promises = []
promises.push(Game.findOne()...)
// Then you do a promise.all
Promise.all(promises )
.then(function(values) {
// Everything was completed successfully
})
.catch(function(err) {
// There was an error with one or all promises handle it here
})
});
别忘了resolve
和reject
在每一个承诺中
这是一篇很好的关于5~6成熟关于承诺的文章
发布于 2018-12-31 18:27:21
您可以使用映射而不是for循环,在映射中返回承诺,然后在映射之后执行Promise.all(mapResult)。这样,promise.all将等待每一个承诺都得到解决。
https://stackoverflow.com/questions/53990370
复制相似问题