如何向来电者发出有关承诺状态的信号

时间:2018-01-19 02:54:58

标签: ember.js rsvp.js rsvp-promise

  • 我有Ember代码,后端API调用被抽象为 单独的服务。该服务使用ember-ajax库进行制作 后端电话。
  • 此服务设置公共标头,处理 超时错误和4xx / 5xx错误。还有像422这样的东西 (验证错误)留待由调用代码处理。

-

 getCustomerProfile (authenticationToken) {
         const backendService = this.get('callBackendService');
         return backendService.callEndpoint(GET_METHOD,
             getCustomerProfileAPI.url,
             {'X-Auth-Token': authenticationToken}).then((customerProfileData) => {
                if (!backendService.get('didAnybodyWin') && customerProfileData) {
                   backendService.set('didAnybodyWin', true);
                   return customerProfileData.profiles[0];
                }
             }).catch((error) => {
                if (isInvalidError(error)) {
                   if (!backendService.get('didAnybodyWin')) {
                      backendService.set('didAnybodyWin', true);
                      backendService.transitionToErrorPage();
                      return;
                   }
                } 
          });
    }

并且call-backend-service看起来像这样

  callEndpoint (httpVerb, endPoint, headersParameter, data = {}, 
   timeoutInMillisecs = backendCallTimeoutInMilliseconds) {
    const headersConst = {
        'Content-Type': 'application/vnd.api+json',
        'Accept': 'application/vnd.api+json',
        'Brand': 'abc'
    };
    var headers = Ember.assign(headersParameter, headersConst);

    var promiseFunctionWrapper;

    this.set('didAnybodyWin', false);
    if (httpVerb.toUpperCase() === GET_METHOD) {
        Ember.Logger.warn('hit GET Method');
        promiseFunctionWrapper = () => {
            return this.get('ajax').request(endPoint, {headers});
        };
    } else if (httpVerb.toUpperCase() === POST_METHOD) {
        Ember.Logger.warn('hit POST Method');
        promiseFunctionWrapper = () => {
            return this.get('ajax').post(endPoint, {data: data, headers: headers});
        };
    } 

    return RSVP.Promise.race([promiseFunctionWrapper(), this.delay(timeoutInMillisecs).then(() => {
        if (!this.get('didAnybodyWin')) {
            this.set('didAnybodyWin', true);
            Ember.Logger.error('timeout of %s happened when calling the endpoint %s', backendCallTimeoutInMilliseconds, endPoint);
            this.transitionToErrorPage();
            return;
        }
    })]).catch((error) => {
        if (!this.get('didAnybodyWin')) {
            if (isTimeoutError(error)) {
                this.set('didAnybodyWin', true);
                Ember.Logger.warn('callBackEndService: isTimeoutError(error) condition is true');
                this.transitionToErrorPage();
                return;
            } else if (isAjaxError(error) && !isInvalidError(error)) { //handles all errors except http 422 (inValid request) 
                    this.set('didAnybodyWin', true);
                    Ember.Logger.warn('callBackEndService: isAjaxError(error) && !isInvalidError(error) [[ non timeout error]] condition is true');
                    this.transitionToErrorPage();
                    return;

            } else {
                throw error;  // to be caught by the caller
            }
        }
    });
},

callEndpoint执行RSVP.Promise.race调用,以确保在超时发生之前回调被调用的后端API。它运行两个承诺,首先解决的是赢得的承诺。 didAnybodyWin 是防止执行承诺的标志。

到目前为止,这一切都很好。

但是这个didAnybodyWin成为了这个call-backend-service的共享状态,因为它必须向调用者传达它是运行默认的then或者catch块还是它希望调用者运行它的then / catch块

问题是当运行model()钩子时,我正在做

RSVP.all {
  backendAPICall1(),
  backendAPICall2(),
  backendAPICAll3()
}

这个RSVP.all将一个接一个地执行所有3个调用,因此它们将以交错方式命中call-backend-service,因此存在相互踩踏的风险(当涉及到didAnybodyWin共享时)状态)。

如何避免这种情况? 是否还有其他更好的方法让被叫方向呼叫者发出信号,告知其是否应该对返回的承诺采取措施。

0 个答案:

没有答案