如何知道异步调用是否完成? (HackerNews评论)

时间:2018-01-08 04:18:11

标签: javascript reactjs rest promise

我正在React / Redux上构建一个hackernews克隆。

在组件内部,Item.js我调用this.props.fetchItem(this.props.match.params.id);

以下是fetchItem动作创建者:

export const fetchItem = (id) => {
    return dispatch => {
        return axios.get(`${ROOT_API_URL}/item/${id}.json`)
            .then(response => {
                let story = response.data;
                let commentIds = response.data.kids; // Story kids
                var allComments = [];

                let fetchComments = commentIdArray => {
                    let promiseArray = [];

                    // 1. Create requests for each commentId
                    commentIdArray.forEach(commentId => {
                        promiseArray.push(axios.get(`${ROOT_API_URL}/item/${commentId}.json`));
                    })

                    // 2. Make requests to fetch all commentIds
                    axios.all(promiseArray)
                        .then(responseArray => {
                            responseArray.forEach(response => {
                                let comment = response.data;
                                allComments.push(comment);

                                if(comment.kids){
                                    fetchComments(comment.kids);
                                }else{
                                    return false;
                                }
                            })
                            console.log("allComments: ", allComments);
                        })
                        .catch(error => {
                            console.log("error promise.all: ", error);
                        })
                }

                fetchComments(commentIds)
            })
            .catch(error => {
                if(error.response.status === 401){
                    console.error("Unauthorized");
                }else{
                    console.error("Something went wrong!");
                }
            })
    }
}

基本上,它接收故事的id并获取该故事的评论。这部分也有效。我在扁平阵列中得到了所有评论。

这是问题所在。我必须在fetchItemSuccess中的某处调用fetchItem,以便我可以将数据保存到redux。虽然,我不知道有多少评论,我通过他们的子评论递归地提取它们。

那么,我如何知道我已准备好所有评论,然后致电fetchItemSuccess

一个故事:https://hacker-news.firebaseio.com/v0/item/8863.json?print=pretty

评论:https://hacker-news.firebaseio.com/v0/item/8952.json?print=pretty

2 个答案:

答案 0 :(得分:0)

以下是一个示例,说明您的源的结构可能会更加健全:

const fetchComments = function(commentIdArray) {
  const promiseArray = [];

  // 1. Create requests for each commentId
  commentIdArray.forEach(commentId => {
    promiseArray.push(axios.get(`${ROOT_API_URL}/item/${commentId}.json`));
  });

  let parentCommentsComments = [];

  return axois.all(promiseArray).then(responseArray => {

    responseArray.forEach(response => {

      const comment = response.data;
      parentComments.push(comment);
      if (comment.kids) {
        return fetchComments(comment.kids);
      } else {
        return [];
      }
    });

  }).then(kidsComments => {

    return parentComments.concat(kidsComments); 

  });

});

export const fetchItem = (id) => {
  return dispatch => {
    return axios.get(`${ROOT_API_URL}/item/${id}.json`)
      .then(response => {
        const story = response.data;
        const commentIds = response.data.kids; // Story kids

        return fetchComments(commentIds);

      })
      .then(comments => {

        // do something with comments?

      })
      .catch(error => {
         if(error.response.status === 401){
           console.error("Unauthorized");
         }else{
           console.error("Something went wrong!");
        }
     })
  }
}

答案 1 :(得分:0)

想通了。

我只需要跟踪异步方法调用。所以,我添加了一个计数变量。如果count为零,则发送一个动作。

export const fetchItem = (id) => {
    return dispatch => {
        return axios.get(`${ROOT_API_URL}/item/${id}.json`)
            .then(response => {
                let story = response.data;
                let commentIds = response.data.kids; // Story kids
                var allComments = [];
                var count = 0; // <=== New Line

                let fetchComments = (commentIdArray) => {
                    let promiseArray = [];
                    count++; // <=== New Line

                    // 1. Create requests for each commentId
                    commentIdArray.forEach(commentId => {
                        promiseArray.push(axios.get(`${ROOT_API_URL}/item/${commentId}.json`));
                    })
                    // 2. Make requests to fetch all commentIds
                    axios.all(promiseArray)
                        .then(responseArray => {
                            responseArray.forEach(response => {
                                let comment = response.data;
                                allComments.push(comment);

                                if(comment.kids){
                                    fetchComments(comment.kids);
                                }else{
                                    return false;
                                }
                            })
                            count--; // <=== New Line
                            if(count === 0){ // <=== New Line
                                dispatch( fetchItemSuccess(allComments) );
                            }
                        })
                        .catch(error => {
                            console.log("error promise.all: ", error);
                        })
                }

                fetchComments(commentIds);
            })
            .catch(error => {
                if(error.response.status === 401){
                    console.error("Unauthorized");
                }else{
                    console.error("Something went wrong!");
                }
            })
    }
}