以更易读的方式编写嵌套的Promise

时间:2018-01-21 09:45:21

标签: node.js promise bluebird

如何通过维护异步/并发流和结果格式,以更易读的方式编写下面的代码。

var getUsers = () => axios.get("URL").then(res => res.data);

var getPosts = id => axios.get("URL").then(res => res.data);

var getComments = id => axios.get("URL").then(res => res.data);

Promise.map(getUsers(), user => {
return getPosts(user.id).then(posts => {
    return Promise.map(posts, post => {
        return getComments(post.id).then(comments => {
            post["comments"] = comments;
            user["posts"] = posts;
            return user;
        });
    });
});
})

.then(res => console.log(JSON.stringify(res)))
.catch(err => console.log(err));

样本格式:

[
{
 id:''
 name:'..',
 email:'',
 phone:''
 posts:[
        {
         postId:'...',
         title:'....'
         body:'....'
         comments: [{body:'....'},{body:'...'}]},
         {
         postId:'...',
         title:'....'
         body:'....'
         comments: [{body:'....'},{body:'...'}]
         }
        ]
  }
]

除了下面的getUsers()之外的每个api都取决于某些args的先前api。 我正在使用蓝鸟承诺库。 Node Js版本:v9.3.0

编辑:我也尝试过使用3 Promise.map:

var getPosts = id => axios.get("URL").then(res => res.data).then(posts => {
        user["posts"] = posts;
        return user;
    });

var getComments = user => {
return Promise.map(user.posts, post => {
    return axios.get(URL).then(res => res.data).then(comments => {
            post["comments"] = comments;
            return user;
        }).then(users => users[0]);

getUsers()
.then(users => Promise.map(users, getPosts))
.then(users => Promise.map(users, getComments))
.then(res => console.log(JSON.stringify(res)))
.catch(err => console.log(err));

2 个答案:

答案 0 :(得分:0)

为了使您的代码更具可读性,并防止丑陋Promise hell您应该使用async/await语法。

async function foo() {
    async function getUsers() {
        var res = await axios.get("URL")
        return res.data
    }

    async function getPosts(id) {
        var res = await axios.get("URL")
        return res.data
    }

    async function getComments(id) {
        var res = await axios.get("URL")
        return res.data
    }

    var users = await getUsers()
    for (var user of users) {
        var posts = await getPosts(user.id)
        for (var p of posts) {
            var comments = await getComments(p.id)
            p['comments'] = comments
        }
        user['posts'] = posts
    }
    return users 
}

然后你就像这样使用

foo()
.then(users => console.log(users))
.catch(e => console.log('Whatever throw or reject inside foo', e))

如果是我,我会做这样的事情

async function foo() {
    var users = await axios.get("users URL")
    for (var user of users.data) {
        var posts = await axios.get("post URL" + user.id)
        for (var p of posts.data) {
            var comments = await axios.get("comments URL" + p.id)
            p['comments'] = comments.data
        }
        user['posts'] = posts.data
    }
    return users.data
}

答案 1 :(得分:0)

我不会说它特别难以辨认。循环需要嵌套。一个小的改进可能是使用prototype .map method而不是Promise.map

getUsers().map(user =>
    getPosts(user.id).map(post => {
        getComments(post.id).then(…)
    )
).then(res =>
    console.log(JSON.stringify(res))
).catch(err =>
    console.error(err)
);

但是,您的代码中似乎存在严重错误。您正在将帖子映射到用户,这会导致用户为他发布的每个帖子重复,并省略完全没有帖子的用户。这可能不是你想要的。相反,在获取帖子和评论后返回用户。

getUsers().map(user =>
    getPosts(user.id).map(post => {
        getComments(post.id).then(comments => {
            post["comments"] = comments;
            return post;
        })
    ).then(posts => {
        user["posts"] = posts;
        return user;
    })
).then(users => {
    console.log(JSON.stringify(users));
}).catch(console.error);

或者我们可以保留我们正在改变其内容的数组,但是如果我们想要访问数组,我们需要使用then而不是map

getUsers().then(users =>
    Promise.map(users, user =>
        getPosts(user.id).then(posts => {
            user.posts = posts;
            return Promise.map(posts, post =>
                getComments(post.id).then(comments => {
                    post["comments"] = comments;
                })
            );
        })
    ).then(() =>
        console.log(JSON.stringify(users))
    )
).catch(console.error);