【问题标题】:Promise nested deep mapPromise 嵌套深度图
【发布时间】:2016-05-25 10:28:24
【问题描述】:

我正在尝试使用 Promise 使事情变得简单,但它似乎是一个真正的噩梦。我想我错过了一些东西。

我愿意:

  1. 在数据库中获取一些文章
  2. 查看找到的每篇文章并遍历 article.authors 数组。
  3. 在每篇文章的数据库(包括 author.images)中获取每个作者
  4. 将第一步中的文章列表发回给客户,但使用 article.authors.images 进行了更新

我尝试了几种使用 Map / Each / spread / Reduce / _.clone / _cloneDeep 的方法

但没有什么能按预期工作

任何帮助将不胜感激

return Promise.bind({})
        .then(function find_article(){
            return Article.find().sort(req.params.sort).skip(req.params.page).limit(req.params.limit).populateAll()
        }).then(function(articles){
            dataBack = articles
            var articlesPromise =  Promise.map(articles,function(article){
                console.log('------------');
                var AuthorsPromise = Promise.map(article.authors,function(author){
                    return User.findOne(author.id).populateAll().then(function(){
                    })
                })
                return Promise.all(AuthorsPromise).then(function(data){
                    console.log('*******************************');
                    console.log(data);
                    return data
                })

            })
            return Promise.all(articlesPromise).then(function(allArticles){
                    console.log('++++++++++++++++++++++++++++++');

                console.log(allArticles);
            })
        })
        .then(function(WhatIsInThere){
            console.log('somethinAfter');
            console.log(WhatIsInThere);
        })

我得到了这样的东西,但仍然不起作用我仍然错过了 .all() 的要点

【问题讨论】:

  • 您使用的是哪个数据库,这是相关的,因为一旦您的数据库开始增长,您构建查询的方式将杀死您的服务器
  • 至于问题,将您的任务模块化为单独的步骤。第 1 步,使用包装在 Promise 中的数据库查询获取文章。第 2 步,函数使用 Promise.all 获取文章数组,并为每篇文章返回另一个模块化的 Promise.all,再次获取作者并在数据库查找时返回作者图像。顶级 api 将调用第一个模块,并链接其他模块
  • 如果您已经使用过Promise.map,则无需再拨打Promise.all。注意Promise.map(arr, f) 等价于Promise.all(arr.map(f))

标签: javascript dictionary promise bluebird


【解决方案1】:

这不是一项简单的任务,您需要链接承诺,并且很可能使用 Promise.all()jQuery.when() 之类的函数

您的代码应如下所示

// function that fetch from database and returns promise
function getArticleFromDatabase(articleId) {
    return new Promise();
}

// function that fetch from database and returns promise
function getAuthorFromDatabase(authorId) {
    return new Promise();
}

var articleIds = [1, 2, 3]; // lets have some array with article ids
// then turn it into array of promises
var articlePromises = articleIds.map(function(articleId) {
    var articlePromise = getArticleFromDatabase(articleId);
    // return the promise
    return articlePromise.then(function(articleData) {
        // here we have available complete article data
        var articleAuthors = articleData.authors; // supose it's array of author ids
        // lets turn it into author data promises
        var authorsPromises = articleAuthors.map(function(author) {
            return getAuthorFromDatabase(author.id);
        });

        // return new Promise, so our first promise of article data
        // will return promise of article data with authors data
        return Promise.all(authorsPromises)
            .then(function(fullfilledAuthorsData) {
                // fill in authors data
                articleData.authors = fullfilledAuthorsData;
                // return complete article data with authors data
                return articleData;
            });
    });
});

Promise.all(articlePromises).then(function(fullfilledArticleData) {
    // here you have available complete article data from all articles
    // fullfilledActicledata is array mapped from initial array of ids
    // so fullfilledActicleData[0] has data for articleIds[0],
    // fullfilledActicleData[1] has data for articleIds[1] etc.
    // You can use the fullfilledArticleData freely.
});

根据您的代码

// this method obviously returns Promise already
var articlesPromise = Article
    .find()
    .sort(req.params.sort)
    .skip(req.params.page)
    .limit(req.params.limit)
    .populateAll();

// attach callback via .then()
articlesPromise
    .then(function(articles) {   
        // here we have fullfilled articles data already
        var articlesWithAuthorsPromises = articles.map(function(article) {
            var authorsPromises = article.authors.map(function(author) {
                return User.findOne(author.id).populateAll();
            });

            return Promise.all(authorsPromises)
                  .then(function(fullfilledAuthors) {
                      article.authors = fullfilledAuthors;
                      return article;
                   })
        })

        // return new Promise
        return Promise.all(articlesWithAuthorsPromises)
    })
    // attach another callback via .then()
   .then(function(fullData) {
        console.log(fullData);
    })
    // you should also listen for errors
    .catch(errorCallback)

【讨论】:

  • 感谢您这么快回答。问题是:在我从数据库中获取它们之前,我没有文章的 ID。
  • @Oldwo1f 文章 ID 并不重要,它们只是说明性的。重要的部分是链接承诺,因此在第一个承诺的回调中,您构建并返回另一个具有回调的承诺,它将来自第一个和第二个承诺的数据组合并返回另一个完整数据的承诺。
  • 是的,但是当我处理多篇文章和作者时,我无法将它们全部恢复。另一件事是,我使用 Waterline ORM,并且在覆盖属性之前我需要 _.clone 或 toObject 我的项目(请参阅此处stackoverflow.com/questions/26535727/…
  • 问题是:我得到这个为我的 fetchOneArticle 方法工作。当我想获取多篇文章时追加问题
  • 是的,您可能需要先调用toObject(),然后再将articles 视为JS 对象。但是,如果你使用 ORM,应该有一些方法可以获取已经加入作者数据的文章。我不知道 Waterline,但对于大多数数据库来说,这应该相当简单。
猜你喜欢
  • 1970-01-01
  • 2015-11-13
  • 2012-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多