【问题标题】:Writing nested Promises in more readable way以更易读的方式编写嵌套的 Promise
【发布时间】:2018-01-26 15:13:50
【问题描述】:

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

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));

【问题讨论】:

  • 嵌套提供了闭包。闭包在这里非常有用。建议你坚持你所拥有的。它不是特别难读。
  • user.posts = posts 可以移出一层。

标签: node.js promise bluebird


【解决方案1】:

为了使您的代码更具可读性并防止丑陋的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
}

【讨论】:

  • OP 确实明确要求“维护异步/并发流”。
  • 他说通过维护异步/并发来提高可读性,因此承诺地狱与维护时的效率无关
  • @FernandoCarvajal 感谢您的回复,但 bergi 是对的
【解决方案2】:

我不会说它特别难读。循环需要嵌套。一个小的改进可能是使用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)
);

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

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);

【讨论】:

    猜你喜欢
    • 2022-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多