如何知道异步调用是否已完成?(黑客新闻评论)



我正在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 并获取该故事的评论。这部分也有效。我在一个扁平的数组中得到了所有评论。

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

那么,我怎么知道我已经准备好了所有评论,然后打电话给fetchItemSuccess

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

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

通了。

我只需要跟踪异步方法调用。因此,我添加了一个计数变量。如果计数为零,则调度操作。

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!");
                }
            })
    }
}

下面是一个示例,说明您的源结构可能更合理一些:

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!");
        }
     })
  }
}

最新更新