强制异步调用同步行为

时间:2016-05-25 19:16:46

标签: javascript asynchronous reactjs microservices

在我的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(...)完成响应?

2 个答案:

答案 0 :(得分:1)

我认为你不明白诺言是如何运作的。

首先,函数总是立即返回,因此您不会阻止执行下一行代码(flight.settheNextSyncFunction())。这是返回承诺的重点:您立即获得承诺 ,您可以附加一个回调(使用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