首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >与Javascript中的操作相比,等待循环结束的最优雅的方法是什么?

与Javascript中的操作相比,等待循环结束的最优雅的方法是什么?
EN

Stack Overflow用户
提问于 2018-12-31 18:23:25
回答 3查看 78关注 0票数 0

我有一个for循环,在这个循环中,我迭代了一组来自json的大约50个对象。在每次迭代中,我都创建一个对象并将其推入数组中。我的意图是,在for循环结束之后,我的数组也完成了,现在我想把这个数组作为对象的一部分推入一个猫鼬集合中。

当然,问题是,当以同步方式编写它时,我会将一个空数组推送到Mongo,因为它不会等待循环结束。现在,我以前做的是一些丑陋的事情。我等待for循环中的我成为array.length -1,然后将推送处理到DB部分。这里的问题是,由于JS的异步特性,它不能保证获得迭代array.length -1可以在JS-3之前运行的所有结果,但我并不介意返回。

现在,我需要数组中的所有迭代。

代码语言:javascript
运行
复制
    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相同,以此类推。

谢谢

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-12-31 18:46:29

这个问题的关键,以及所有这些关于S.O.的问题,都是看森林而不是看树。从高层开始,你真正需要的是:

代码语言:javascript
运行
复制
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是最简单的方法:

代码语言:javascript
运行
复制
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个并发请求。这可能很好,但一般来说,您希望确保您正在使用的客户端具有内置节流阀,或者自己添加一个节流阀。(蓝鸟提供了一个易于使用的并发选项,用于需要自己动手的情况。)

票数 2
EN

Stack Overflow用户

发布于 2018-12-31 18:38:43

您最好的选择是使用异步库。很简单也很受欢迎的图书馆。

这是一个如何使用它的例子。

代码语言:javascript
运行
复制
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()...时,您都会执行一系列承诺。

类似于这个(记住这不是完整的代码,它只是一个例子)

代码语言:javascript
运行
复制
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
    })
});

别忘了resolvereject在每一个承诺中

这是一篇很好的关于5~6成熟关于承诺的文章

票数 2
EN

Stack Overflow用户

发布于 2018-12-31 18:27:21

您可以使用映射而不是for循环,在映射中返回承诺,然后在映射之后执行Promise.all(mapResult)。这样,promise.all将等待每一个承诺都得到解决。

像这样的https://stackoverflow.com/a/53982910/9661304

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53990370

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档