如何在 React 中执行下一个函数之前完成所有提取?
How to finish all fetch before executing next function in React?
使用 ReactJS,我有两个不同的 API 点,我正在尝试获取和重组:students
和 scores
。它们都是一个对象数组。
我的目标是:首先,获取学生和分数,其次,将学生和分数保存在状态中,我将修改它们并创建一个基于学生和分数的新状态分数状态。简而言之,我有 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)
};
然后我将它们组合在一起:
function getStudentsAndScores(cbStudent, cbScores, cbStudentsScores){
getStudents(cbStudent).then(getScores(cbScores)).then(cbStudentsScores);
}
在我的 React 应用程序中,我有以下内容:
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
和 this.state.scores
在 运行 rearrangeStudentsWithScores
之前都已加载?
您的代码混合了 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);
})
这种方法不仅更简单,而且效率更高,因为它同时发出两个请求;你的方法是等到学生被取走后再取分数。
我会建议稍微重组 - 不要在每次提取调用完成后更新您的状态,而是等待两者都完成,然后一次更新所有状态。然后你可以使用 setState
callback method 到 运行 你想要的下一个方法。
您可以使用 Bluebird 等 Promise 库来等待多个获取请求完成,然后再执行其他操作
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);
});
我认为您需要将函数包装在箭头函数中。这些函数在编译承诺链并发送到事件循环时被调用。这会造成竞争条件。
function getStudentsAndScores(cbStudent, cbScores, cbStudentsScores){
getStudents(cbStudent).then(() => getScores(cbScores)).then(cbStudentsScores);
}
我推荐这篇文章作为补充阅读:
We Have a Problem with Promises by Nolan Lawson
这是我创建的一个存储库,其中包含文章中讨论的每个概念的示例。
Pinky Swear
使用 ReactJS,我有两个不同的 API 点,我正在尝试获取和重组:students
和 scores
。它们都是一个对象数组。
我的目标是:首先,获取学生和分数,其次,将学生和分数保存在状态中,我将修改它们并创建一个基于学生和分数的新状态分数状态。简而言之,我有 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)
};
然后我将它们组合在一起:
function getStudentsAndScores(cbStudent, cbScores, cbStudentsScores){
getStudents(cbStudent).then(getScores(cbScores)).then(cbStudentsScores);
}
在我的 React 应用程序中,我有以下内容:
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
和 this.state.scores
在 运行 rearrangeStudentsWithScores
之前都已加载?
您的代码混合了 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);
})
这种方法不仅更简单,而且效率更高,因为它同时发出两个请求;你的方法是等到学生被取走后再取分数。
我会建议稍微重组 - 不要在每次提取调用完成后更新您的状态,而是等待两者都完成,然后一次更新所有状态。然后你可以使用 setState
callback method 到 运行 你想要的下一个方法。
您可以使用 Bluebird 等 Promise 库来等待多个获取请求完成,然后再执行其他操作
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);
});
我认为您需要将函数包装在箭头函数中。这些函数在编译承诺链并发送到事件循环时被调用。这会造成竞争条件。
function getStudentsAndScores(cbStudent, cbScores, cbStudentsScores){
getStudents(cbStudent).then(() => getScores(cbScores)).then(cbStudentsScores);
}
我推荐这篇文章作为补充阅读: We Have a Problem with Promises by Nolan Lawson
这是我创建的一个存储库,其中包含文章中讨论的每个概念的示例。 Pinky Swear