在我的React应用中,我尝试根据其他三个值计算一个值。我已经包含了后端的所有计算逻辑,这是一个我进行异步调用的微服务。我异步尝试获取该计算值的函数位于许多同步挂钩的中间。
在UI层,我调用我想要返回最终结果的函数(异步返回)。该调用函数调用另一个函数,该函数调用另一个函数,该函数返回一个新的Promise。请参阅以下代码:
// DateUI.js (layer 1)
selectDate(dateField, flight, idx, saved, momentTime, e) {
if (moment(momentTime).isValid()) {
if (dateField == "StartDate") {
// The initial problematic function call, need to set endDate before I continue on
let endDate = PlanLineActions.calculateFlightEndDate(periodTypeId, numberOfPeriods, momentTimeUnix);
flight.set("EndDate", endDate);
}
this.theNextSyncFunction(..., ..., ...);
}
}
// DateActions.js (layer 2)
calculateFlightEndDate(periodTypeId, numberOfPeriods, startDate) {
let plan = new Plan();
plan.getFlightEndDate(periodTypeId, numberOfPeriods, startDate).then(function(response) {
// response is JSON: {EndDate: "12/05/2016"}
response.EndDate;
}, function(error) {
log.debug("There was an error calculating the End Date.");
});
}
// DateClass.js (layer 3)
getFlightEndDate(periodTypeId, numberOfPeriods, startDate) {
let path = '/path/to/microservice';
return this.callServer(path, 'GET', {periodTypeId: periodTypeId, numberOfPeriods: numberOfPeriods, startDate: startDate});
}
// ServerLayer.js (layer 4)
callServer(path, method = "GET", query = {}, data, inject) {
return new Promise((resolve, reject) => {
super.callServer(uri.toString(),method,data,inject).then((data) => {
resolve(data);
}).catch((data) => {
if (data.status === 401) {
AppActions.doRefresh();
}
reject(data);
});
});
}
我的印象是,因为ServerLayer.js(第4层)返回new Promise
(因此返回DateClass.js(第3层)),所以在响应到来之前调用plan.getFlightEndDate(...).then(function(response) {...
将无法完成回复或拒绝。目前还没有发生这种情况,因为DateUI.js(第1层)中的代码将继续调用this.theNextSyncFunction
,然后使用正确的数据解决约50ms。
在继续使用selectDate()之前,如何在DateUI.js(第1层)中强制PlanLineActions.calculateFlightEndDate(...)完成响应?
答案 0 :(得分:1)
我认为你不明白诺言是如何运作的。
首先,函数总是立即返回,因此您不会阻止执行下一行代码(flight.set
和theNextSyncFunction()
)。这是返回承诺的重点:您立即获得承诺 ,您可以附加一个回调(使用then()
),稍后将调用 。如果您希望代码等待承诺解决,必须将其置于then()
回调中。
其次,您的calculateFlightEndDate()
根本没有返回任何内容,因此endDate = calculateFlightEndDate()
只是将endDate
设置为undefined
。
您应该从calculateFlightEndDate()
返回一个承诺,然后将您想要执行的代码放入then()
回调中:
calculateFlightEndDate(periodTypeId, numberOfPeriods, startDate) {
let plan = new Plan();
return plan.getFlightEndDate(periodTypeId, numberOfPeriods, startDate).then((response) => {
// response is JSON: {EndDate: "12/05/2016"}
return response.EndDate;
}, (error) => {
log.debug("There was an error calculating the End Date.");
});
}
if (moment(momentTime).isValid()) {
if (dateField == "StartDate") {
PlanLineActions.calculateFlightEndDate(periodTypeId, numberOfPeriods, momentTimeUnix).then((endDate) => {
flight.set("EndDate", endDate);
this.theNextSyncFunction(...);
});
}
}
您还可以考虑使用ES7 async
and await
,它允许您编写您的异步代码,以便看起来同步,但使用承诺来实现同样的事情。
答案 1 :(得分:1)
如果它像ajax调用一样超出事件循环,你就不能强迫某些东西是同步的。你需要的东西看起来像这样:
lein new
为了做到这一点,PlanLineActions.calculateFlightEndDate(periodTypeId, numberOfPeriods, momentTimeUnix)
.then(endDate => {
this.theNextSyncFunction(..., ..., ...);
})
还需要返回一个承诺,因此承诺可以链接是一件好事。
calculateFlightEndDate
应该这样做..还有一件事:你在服务器调用中加倍承诺。如果某事已经calculateFlightEndDate(periodTypeId, numberOfPeriods, startDate) {
let plan = new Plan();
// return promise!
return plan.getFlightEndDate(periodTypeId, numberOfPeriods, startDate).then(response => {
return response.EndDate; // must return here
}, error => {
log.debug("There was an error calculating the End Date.");
});
}
它已经是一个承诺,那么你可以直接返回它。无需包裹.then
(承诺中的承诺......不需要!)
new Promise