使用ReactJS,我有两个不同的API点,我正在尝试获取和重组:Select Left(ColA,3) As NewCol from TableA
和students
。它们都是一组对象。
我的目标是:首先,获得学生和分数,其次,学生和分数保存在州,我将修改它们并根据学生和分数状态创建新状态。简而言之,我有3个功能:scores
,getStudents
和getScores
。 <{1}}和rearrangeStudentsAndScores
需要在getStudents
运行之前完成。
我的问题是:有时getScores
会在rearrangeStudentsAndScores
完成之前运行。那混乱了rearrangeStudentsAndScores
。但有时它会完成。不确定为什么它在50%的时间都有效,但我需要让它在100%的时间内都能正常工作。
这就是我在getScores
文件中rearrangeStudentsAndScores
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)
};
不知何故,当我到达function getStudentsAndScores(cbStudent, cbScores, cbStudentsScores){
getStudents(cbStudent).then(getScores(cbScores)).then(cbStudentsScores);
}
时,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;
...
}
}
仍然是rearrangeStudentsWithScores
。
在运行this.state.scores
之前,如何确保[]
和this.state.students
都已加载?
答案 0 :(得分:28)
您的代码混合了continuation callbacks和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);
})
除了更简单之外,这种方法更有效,因为它同时发出两个请求;在取得分数之前,你的方法一直等到学生被取出。
答案 1 :(得分:2)
我相信你需要将你的函数包装在箭头函数中。在编译promise链并将其发送到事件循环时,将调用这些函数。这造成了竞争条件。
function getStudentsAndScores(cbStudent, cbScores, cbStudentsScores){
getStudents(cbStudent).then(() => getScores(cbScores)).then(cbStudentsScores);
}
我推荐这篇文章进行额外阅读: We Have a Problem with Promises by Nolan Lawson
这里有一个我做的回购,它为本文中提到的每个概念都有一个例子。 Pinky Swear
答案 2 :(得分:0)
我建议稍微重组 - 而不是在每次提取调用完成后更新您的状态,等待两者完成,然后立即更新状态。然后,您可以使用setState
callback method运行您想要的下一个方法。
您可以使用Promise库(例如Bluebird)等待多个获取请求完成,然后再执行其他操作
import Promise from 'bluebird'
getStudents = () => {
return fetch(`api/students`, {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}).then(response => response.json());
};
getScores = () => {
return fetch(`api/scores`, {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}).then(response => response.json());
};
Promise.join(getStudents(), getScores(), (students, scores) => {
this.setState({
students,
scores
}, this.rearrangeStudentsWithScores);
});