强制执行:从猫鼬回调中返回值或将值推入新数组值

时间:2018-10-10 15:10:02

标签: javascript node.js mongodb asynchronous mongoose

  

实际上,如果您认为我的问题的标题不正确,   有任何想法,您可以发表评论,我将其重命名。

我试图重写我的旧函数,该函数发出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问题,这可能对我的情况有用。

2 个答案:

答案 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)
    }   
}