如何在React中执行下一个函数之前完成所有获取?

Igg*_*ggy 20 javascript asynchronous fetch reactjs

使用ReactJS,我有两个不同的API点,我试图得到和重组:studentsscores.它们都是一个对象数组.

我的目标是:首先,获得学生和分数,其次,学生和分数保存在州,我将修改它们并根据学生和分数状态创建一个新状态.总之,我有3个功能:getStudents,getScores,和rearrangeStudentsAndScores.getStudents并且getScores需要在完成之前完成rearrangeStudentsAndScores.

我的问题是:有时rearrangeStudentsAndScores会在getScores完成之前运行.那搞砸rearrangeStudentsAndScores了.但有时它会完成.不确定为什么它在50%的时间都有效,但我需要让它在100%的时间内都能正常工作.

这是我fetch students and scores在我的Client文件中所要做的:

function getStudents(cb){
    return fetch(`api/students`, {
        headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        }
    }).then((response) => response.json())
    .then(cb)
};

function getScores(cb){
    return fetch(`api/scores`, {
        headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        }
    }).then((response) => response.json())
    .then(cb)
};
Run Code Online (Sandbox Code Playgroud)

然后我把它们组合在一起:

function getStudentsAndScores(cbStudent, cbScores, cbStudentsScores){
    getStudents(cbStudent).then(getScores(cbScores)).then(cbStudentsScores);
}
Run Code Online (Sandbox Code Playgroud)

在我的反应应用程序中,我有以下内容:

getStudentsAndScores(){
    Client.getStudentsAndScores(
        (students) => {this.setState({students})},
        (scores) => {this.setState({scores})},
        this.rearrangeStudentsWithScores
    )
}

rearrangeStudentsWithScores(){
    console.log('hello rearrange!')
    console.log('students:')
    console.log(this.state.students);
    console.log('scores:');
    console.log(this.state.scores);        //this returns [] half of the time
    if (this.state.students.length > 0){
        const studentsScores = {};
        const students = this.state.students;
        const scores = this.state.scores;
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

不知何故,当我到达时rearrangeStudentsWithScores,this.state.scores仍将是[].

在运行之前,如何确保this.state.students并且this.state.scores都已加载rearrangeStudentsWithScores

joe*_*ews 37

您的代码混合了延续回调和Promises.您会发现使用一种方法进行异步流控制更容易推理它.让我们使用Promises,因为fetch使用它们.

// Refactor getStudents and getScores to return  Promise for their response bodies
function getStudents(){
  return fetch(`api/students`, {
    headers: {
      'Content-Type': 'application/json',
      'Accept': 'application/json'
    }
  }).then((response) => response.json())
};

function getScores(){
  return fetch(`api/scores`, {
    headers: {
      'Content-Type': 'application/json',
      'Accept': 'application/json'
    }
  }).then((response) => response.json())
};

// Request both students and scores in parallel and return a Promise for both values.
// `Promise.all` returns a new Promise that resolves when all of its arguments resolve.
function getStudentsAndScores(){
  return Promise.all([getStudents(), getScores()])
}

// When this Promise resolves, both values will be available.
getStudentsAndScores()
  .then(([students, scores]) => {
    // both have loaded!
    console.log(students, scores);
  })
Run Code Online (Sandbox Code Playgroud)

除了更简单之外,这种方法更有效,因为它同时发出两个请求; 你的方法一直等到获取学生之前取得分数.

请参阅Promise.allMDN