javascript - 即使我正在使用 Promises,我似乎也无法弄清楚为什么第三个函数在其他两个函数之前运行。我究竟做错了什么?
问题描述
当我 console.log this.state.events 和 this.state.meets 终端记录这两个状态是空数组。这表明该函数在函数 2 和 3 完成之前执行,并且我的承诺是错误的。我似乎无法弄清楚我的问题,我很困惑。我知道 setState 也可以正常工作,因为一旦页面呈现,我就有一个按钮,其功能 console.logs 这些状态并正确执行。
我尝试过以各种方式格式化我的承诺,但我不知道在我的函数完成之前它们是如何解决的。
obtainEventsAndMeetsRefs = () => {
return Promise.resolve(
this.userRef.get().then(
doc => {
this.setState(
{
eventRefs: doc.data().Events,
meetingsRef: doc.data().Meets
}
)
}
)
)
}
obtainEvents() {
var that = this
return new Promise(function (resolve, reject) {
for (i = 0; i < that.state.eventRefs.length; i++) {
docRef = that.state.eventRefs[i]._documentPath._parts[1];
firebase.firestore().collection('All Events').doc(docRef).get().then(
doc => {
that.setState({
events: update(that.state.events, {
$push: [
{
eventName: doc.data().eventName,
eventDescription: doc.data().eventDescription,
startDate: doc.data().startDate,
endDate: doc.data().endDate,
location: doc.data().location,
privacy: doc.data().privacy,
status: doc.data().status,
attending: doc.data().attending
}
]
})
})
}
)
if (i == that.state.eventRefs.length - 1) {
console.log('1')
resolve(true)
}
}
})
}
obtainMeetings() {
var that = this
return new Promise(function (resolve, reject) {
for (i = 0; i < that.state.meetingsRef.length; i++) {
userRef = that.state.meetingsRef[i]._documentPath._parts[1];
meetRef = that.state.meetingsRef[i]._documentPath._parts[3];
ref = firebase.firestore().collection('Users').doc(userRef)
.collection('Meets').doc(meetRef)
ref.get().then(
doc => {
that.setState({
meets: update(that.state.meets, {
$push: [
{
headline: doc.data().headline,
agenda: doc.data().agenda,
startTime: doc.data().startTime,
endTime: doc.data().endTime,
date: doc.data().date,
name: doc.data().name
}
]
})
})
}
)
if (i == that.state.meetingsRef.length - 1) {
console.log('2')
resolve(true)
}
}
})
}
orderByDate = () => {
console.log(this.state.events)
console.log(this.state.meets)
}
componentDidMount() {
this.obtainEventsAndMeetsRefs().then(
() => this.obtainEvents().then(
() => this.obtainMeetings().then(
() => this.orderByDate()
)
)
)
}
我希望输出是一个填充了我使用 setState 输入的数据的数组,而不是一个空数组。
解决方案
问题的症结在于,当异步操作完成时obtainMeetings()
,obtainEvents()
不返回解决的承诺。因此,您无法知道他们的工作何时完成,因此您无法正确地对它们进行排序。
这段代码有各种各样的错误。首先,您不需要将现有的 Promise 包装在另一个 Promise 中(Promise 构造反模式),因为这会导致错误(您正在制作)。相反,您可以只返回现有的承诺。
例如,改变这个:
obtainEventsAndMeetsRefs = () => {
return Promise.resolve(
this.userRef.get().then(
doc => {
this.setState(
{
eventRefs: doc.data().Events,
meetingsRef: doc.data().Meets
}
)
}
)
)
}
对此:
obtainEventsAndMeetsRefs = () => {
return this.userRef.get().then(doc => {
this.setState({
eventRefs: doc.data().Events,
meetingsRef: doc.data().Meets
});
});
}
然后,链接而不是嵌套并返回与操作的完成/错误相关 的承诺。
所以改变这个:
componentDidMount() {
this.obtainEventsAndMeetsRefs().then(
() => this.obtainEvents().then(
() => this.obtainMeetings().then(
() => this.orderByDate()
)
)
)
}
对此:
componentDidMount() {
return this.obtainEventsAndMeetsRefs()
.then(this.obtainEvents.bind(this))
.then(this.obtainMeetings.bind(this))
.then(this.orderByDate.bind(this))
}
或者,如果您愿意:
componentDidMount() {
return this.obtainEventsAndMeetsRefs()
.then(() => this.obtainEvents())
.then(() => this.obtainMeetings())
.then(() => this.orderByDate())
}
这些链而不是嵌套,它们返回一个跟踪整个链的承诺,以便调用者知道链何时完成和/或是否存在错误。
然后,如果你想让你的for
循环串行执行,你可以像这样在循环内的 Promise 上async
使用await
它:
async obtainMeetings() {
for (let i = 0; i < this.state.meetingsRef.length; i++) {
let userRef = this.state.meetingsRef[i]._documentPath._parts[1];
let meetRef = this.state.meetingsRef[i]._documentPath._parts[3];
let ref = firebase.firestore().collection('Users').doc(userRef)
.collection('Meets').doc(meetRef)
// make the for loop wait for this operation to complete
await ref.get().then(doc => {
this.setState({
meets: update(this.state.meets, {
$push: [{
headline: doc.data().headline,
agenda: doc.data().agenda,
startTime: doc.data().startTime,
endTime: doc.data().endTime,
date: doc.data().date,
name: doc.data().name
}]
});
});
});
// this return here isn't making a whole lot of sense
// as your for loop already stops things when this index reaches
// the end value
if (i == this.state.meetingsRef.length - 1) {
console.log('2')
return true;
}
}
// it seems like you probably want to have a return value here
return true;
}
这看起来在您的实现中缺少i
,userRef
和的声明meetRef
也存在问题。ref
这些应该是本地声明的变量。
obtainEvents()
需要同样的重新设计。
如果您不能使用async/await
,那么您可以进行转换,或者您必须设计循环以不同方式工作(更多的是手动异步迭代)。
如果您可以并行运行循环中的所有异步操作,并且只想知道它们何时完成,您可以执行以下操作:
obtainMeetings() {
return Promise.all(this.state.meetingsRef.map(item => {
let userRef = item._documentPath._parts[1];
let meetRef = item._documentPath._parts[3];
let ref = firebase.firestore().collection('Users').doc(userRef)
.collection('Meets').doc(meetRef)
// make the for loop wait for this operation to complete
return ref.get().then(doc => {
this.setState({
meets: update(this.state.meets, {
$push: [{
headline: doc.data().headline,
agenda: doc.data().agenda,
startTime: doc.data().startTime,
endTime: doc.data().endTime,
date: doc.data().date,
name: doc.data().name
}]
});
});
});
})).then(allResults => {
// process all results, decide what the resolved value of the promise should be here
return true;
});
}
推荐阅读
- azure - 如何在 Azure 中查看 Azure Function 主机启动时间?
- three.js - Autodesk Forge Viewer 中的自定义点着色器在正交摄影机上表现异常
- python - 使用 keras、python 训练一个小模型
- sql - 如何在 Select 子句中使用变量
- highcharts - Highcharts折线图中的网格(网格线)
- css - webpack 加载器无法解析某些图像文件
- python-3.x - 如何链式 describe()、value_counts() 和 to_csv()
- github - “git svn”命令不适用于非标准 svn 存储库
- r - 在合并期间通过过滤器(管道?)
- python - Python JupyterLab:在一行停止执行代码