实际上,如果您认为我的问题的标题不正确, 有任何想法,您可以发表评论,我将其重命名。
我试图重写我的旧函数,该函数发出http请求并通过mongoose在mongoDB上插入许多对象。我已经有了它的工作版本,但是在使用时遇到了问题。基本上,因为当我尝试从20个以上的请求中插入20个数组,而一个请求中有〜50'000个元素时,会导致巨大的内存泄漏。即使使用MongoDB优化。
我的代码的逻辑:
function main() {
server.find({locale: "en_GB"}).exec(function (err, server) {
for (let i = 0; i < server.length; i++) { //for example 20 servers
rp({url: server[i].slug}).then(response => {
auctions.count({
server: server[i].name,
lastModified: {$gte: response.data.files[0].lastModified}
}).then(function (docs) {
if (docs < 0) {
//We don't insert data if they are already up-to-date
}
else {
//I needed response.data.files[0].url and server[i].name from prev. block
//And here is my problem
requests & insertMany and then => loop main()
})
}
})
}).catch(function (error) {
console.log(error);
})
}
})
}
main()
实际上,我已经尝试了许多不同的方法来解决它。首先,我试图在else
块之后添加setInterval,如下所示:
setTimeout(function () {
//request every server with interval, instead of all at once
}, 1000 * (i + 1));
但是我为自己创建了另一个问题,因为我需要在之后立即递归main()
函数。因此,我无法使用:if (i === server[i].length-1)
调用垃圾回收器或重新启动main()
,因为并非所有服务器都跳过count
验证
或者让我们看看我的另一个例子:
我将for (let i = 0; i < server.length; i++)
从第三行更改为.map
,并将其从第三行移至靠近else
的位置,但是setTimeout
在{{ 1}}版本,但您可能已经了解脚本丢失了正确的顺序,因此我不能为此延迟。
实际上,我已经知道如何立即修复它。只需使用.map
通过let array_new = [], array_new.push = response.data.files[0].url
重新创建数组。但是我不是专家,所以我已经浪费了几个小时。因此,目前唯一的问题是,我不知道如何从async/await
return
的值
目前,我正在尝试在else block
块内形成数组
else
,然后通过function main() {
--added let array_new = [];
[v1]array_new.url += response.data.files[0].url;
[v2]array_new.push(response.data.files[0].url);
return array_new
调用array_new
数组,但是其中之一目前还不能正常工作。因此,也许有人会给我一个提示或向我展示已经回答的@Stackoverflow问题,这可能对我的情况有用。
答案 0 :(得分:1)
您的问题在于诺言模糊的逻辑。您的main
函数递归调用自己N次,其中N是服务器的数量。这将以指数方式建立以通过节点进程和MongoDB处理所有请求来占用内存。
与其跳入异步/等待状态,不如使用promise开始并等待N个查询的批处理完成,然后再开始另一个批处理。您可以为此使用[Promise.all]。
function main() {
server.find({locale: "en_GB"}).exec(function (err, server) {
// need to keep track of each promise for each server
let promises = []
for (let i = 0; i < server.length; i++) {
let promise = rp({
url: server[i].slug
}).then(function(response) {
// instead of nesting promises, return the promise so it is handled by
// the next then in the chain.
return auctions.count({
server: server[i].name,
lastModified: {
$gte: response.data.files[0].lastModified
}
});
}).then(function (docs) {
if (docs > 0) {
// do whatever you need to here regarding making requests and
// inserting into DB, but don't call main() here.
return requestAndInsert();
}
}).catch(function (error) {
console.log(error);
})
// add the above promise to out list.
promises.push(promise)
}
// register a new promise to run once all of the above promises generated
// by the loop have been completed
Promise.all(promises).then(function () {
// now you can call main again, optionally in a setTimeout so it waits a
// few seconds before fetchin more data.
setTimeout(main, 5000);
})
})
}
main()
答案 1 :(得分:1)
由于本质上是在处理promise,因此可以重构函数逻辑以使用异步等待,如下所示:
function async main() {
try {
const servers = await server.find({locale: "en_GB"}).exec()
const data = servers.map(async ({ name, slug }) => {
const response = await rp({ url: slug })
const { lastModified, url } = response.data.files[0]
const count = await auctions.count({
server: name,
lastModified: { $gte: lastModified }
})
let result = {}
if (count > 0) result = { name, url }
return result
}).filter(d => Object.keys(d).length > 0)
Model.insertMany(data)
} catch (err) {
console.error(err)
}
}