JS Promise API:创建一个promises循环并将结果合并到另一个对象中

时间:2017-06-15 13:52:17

标签: javascript promise bluebird es6-promise

我正在尝试了解Promise API。

测试用例 我正在使用三个API,来自jsonplaceholder

/user/{userId} #Returns a user
/posts?userId=1 #Returs list of posts by user
/comments?postId=1 #Returns list of comments for the post

我需要将所有三个API的输出组合成如下所示的结构。

var user = {
    'id' : "1",
    "name" : "Qwerty",
    "posts" : [
        {
            "id" : 1,
            "userid" : 1,
            "message" : "Hello",
            "comments" : [
                {
                    'id' : 1,
                    "postId" :1
                    "userid" : 2,
                    "message" : "Hi!"                   
                },
                {
                    'id' : 2,
                    "postId" :1
                    "userid" : 1,
                    "message" : "Lets meet at 7!"
                }
            ]
        }
    ]
}

我面临的挑战是将评论合并到每个帖子。请帮忙。我的意思是我不知道该怎么做。

当前实施。

var xyz = function (userId) {
    return Promise.all(
        [
            usersApi.getUsersByIdPromise(userId),
            postsApi.getPostsForUserPromise(userId)
        ]
    ).spread((user, posts) => {
        user.posts = posts;

        for (let post of user.posts){
            commentsApi.getCommentsForPostPromise(post.id)
                .then(comments => {                   
                    //Merge comments to post
                    //How do i return a merged user object
                });
        }        
    })
}

1 个答案:

答案 0 :(得分:2)

你走在正确的轨道上,看到评论:

var xyz = function (userId) {
    // Start parallel requests for user and posts
    return Promise.all(
        [
            usersApi.getUsersByIdPromise(userId),
            postsApi.getPostsForUserPromise(userId)
        ]
    ).then(([user, posts]) => { // Note the destructuring
        // We have both user and posts, let's add the posts to the user
        user.posts = posts;

        // Send parallel queries for all the post comments, by
        // using `map` to get an array of promises for each post's
        // comments
        return Promise.all(user.posts.map(post => 
            commentsApi.getCommentsForPostPromise(post.id)
                .then(comments => {                   
                    // Have the comments for this post, remember them
                    post.comments = comments;
                })
            ))
            // When all of those comments requests are done, set the
            // user as the final resolution value in the chain
            .then(_ => user);
    });
};

示例:



// Mocks
var commentId = 0;
var usersApi = {
    getUsersByIdPromise(userId) {
        return new Promise(resolve => {
            setTimeout(_ => resolve({id: userId, name: "Some User"}), 100);
        });
    }
};
var postsApi = {
    getPostsForUserPromise(userId) {
        return new Promise(resolve => {
            setTimeout(_ => resolve([
                {userId: userId, id: 1, title: "Post 1"},
                {userId: userId, id: 2, title: "Post 2"}
            ]), 100);
        });
    }
};
var commentsApi = {
    getCommentsForPostPromise(postId) {
        return new Promise(resolve => {
            setTimeout(_ => resolve([
                {postId: postId, id: ++commentId, title: "First comment on post id = " + postId},
                {postId: postId, id: ++commentId, title: "Second comment on post id = " + postId},
                {postId: postId, id: ++commentId, title: "Third comment on post id = " + postId}
            ]), 100);
        });
    }
};
// Code
var xyz = function (userId) {
    // Start parallel requests for user and posts
    return Promise.all(
        [
            usersApi.getUsersByIdPromise(userId),
            postsApi.getPostsForUserPromise(userId)
        ]
    ).then(([user, posts]) => { // Note the destructuring
        // We have both user and posts, let's add the posts to the user
        user.posts = posts;

        // Send parallel queries for all the post comments, by
        // using `map` to get an array of promises for each post's
        // comments
        return Promise.all(user.posts.map(post => 
            commentsApi.getCommentsForPostPromise(post.id)
                .then(comments => {                   
                    // Have the comments for this post, remember them
                    post.comments = comments;
                })
            ))
            // When all of those comments requests are done, set the
            // user as the final resolution value in the chain
            .then(_ => user);
    });
};
// Using it
xyz().then(user => {
    console.log(JSON.stringify(user, null, 2));
});

.as-console-wrapper {
  max-height: 100% !important;
}




虽然实际上,我们可以在收到帖子后立即开始请求帖子的评论,而不会等到用户直到以后:

var xyz = function (userId) {
    return Promise.all(
        [
            usersApi.getUsersByIdPromise(userId),
            postsApi.getPostsForUserPromise(userId).then(posts =>
                // We have the posts, start parallel requests for their comments
                Promise.all(posts.map(post => 
                    commentsApi.getCommentsForPostPromise(post.id)
                        .then(comments => {
                            // Have the post's comments, remember them
                            post.comments = comments;
                        })
                ))
                // We have all the comments, resolve with posts
                .then(_ => posts)
            )
        ]
    ).then(([user, posts]) => { // Note the destructuring
        // We have both user and posts (with their filled-in comments)
        // Remember the posts on the user, and return the user as the final
        // resolution value in the chain
        user.posts = posts;
        return user;
    });
};

示例:



// Mocks
var commentId = 0;
var usersApi = {
    getUsersByIdPromise(userId) {
        return new Promise(resolve => {
            setTimeout(_ => resolve({id: userId, name: "Some User"}), 100);
        });
    }
};
var postsApi = {
    getPostsForUserPromise(userId) {
        return new Promise(resolve => {
            setTimeout(_ => resolve([
                {userId: userId, id: 1, title: "Post 1"},
                {userId: userId, id: 2, title: "Post 2"}
            ]), 100);
        });
    }
};
var commentsApi = {
    getCommentsForPostPromise(postId) {
        return new Promise(resolve => {
            setTimeout(_ => resolve([
                {postId: postId, id: ++commentId, title: "First comment on post id = " + postId},
                {postId: postId, id: ++commentId, title: "Second comment on post id = " + postId},
                {postId: postId, id: ++commentId, title: "Third comment on post id = " + postId}
            ]), 100);
        });
    }
};
// Code
var xyz = function (userId) {
    return Promise.all(
        [
            usersApi.getUsersByIdPromise(userId),
            postsApi.getPostsForUserPromise(userId).then(posts =>
                // We have the posts, start parallel requests for their comments
                Promise.all(posts.map(post => 
                    commentsApi.getCommentsForPostPromise(post.id)
                        .then(comments => {
                            // Have the post's comments, remember them
                            post.comments = comments;
                        })
                ))
                // We have all the comments, resolve with posts
                .then(_ => posts)
            )
        ]
    ).then(([user, posts]) => { // Note the destructuring
        // We have both user and posts (with their filled-in comments)
        // Remember the posts on the user, and return the user as the final
        // resolution value in the chain
        user.posts = posts;
        return user;
    });
};
// Using it
xyz().then(user => {
    console.log(JSON.stringify(user, null, 2));
});

.as-console-wrapper {
  max-height: 100% !important;
}