在 for 循环打字稿和休眠死锁中调用异步函数

Posted

技术标签:

【中文标题】在 for 循环打字稿和休眠死锁中调用异步函数【英文标题】:Calling an asynchronous function within a for loop typescript and nhibernate deadlock 【发布时间】:2019-02-07 19:54:29 【问题描述】:

我正在使用 typescript 在 for 循环中编写一个 http post 调用。

在后端调试方法时,我注意到他同时处理请求。

例如,假设服务器必须在每个请求中运行 2 个方法 M1() 然后 M2()。对于 n = 2 的测试用例。服务器对请求 1 执行 M1(),对请求 2 执行 M1(),然后对请求 2 执行 M2(),最后对请求 2 执行 M2()

那么在_session.commit()之后,方法intercept中会抛出一个异常。异常描述为:

NHibernate.StaleObjectStateException: '行已被另一个事务更新或删除(或未保存的值映射不正确):[Server.Model.Identity.ApplicationRole#3]'

代码:

public calculate(index?: number): void 
    for (var i = 0; i < this.policy.coverages.length; i++) 
        this.callCalculate(i);
    


public callCalculate(i: number): void 
    this.premiumCalculationParams = this.policy.createPremiumCalculationParams();

    if (!this.premiums) 
        this.premiums = new Array(this.policy.coverages.length);
    

    this.offerService.calculatePremiums(this.policy, i).then((result: any) => 

        this.premiums[i] = new Array<Premium>();
        this.surpremiums = new Array<PremiumResult>();

        if (result.data && result.data.premiumTable && result.data.premiumTable.premiumPayment && result.data.premiumTable.premiumPayment.premiums && result.data.premiumTable.premiumPayment.premiums.length > 0) 
            _.each(result.data.premiumTable.premiumPayment.premiums, (premiumValue: any) => 
                let premium: Premium = new Premium();
                premium.setPremium(premiumValue);
                this.premiums[i].push(premium);
                this.policy.getCoverage(i).premiumPayment.premiums = angular.copy(this.premiums[i]);
            );

            if (result.data && result.data.results && result.data.results.length > 0) 
                _.each(result.data.results, (premiumValuel: any) => 
                    let sp = new PremiumResult();
                    sp.setPremiumResult(premiumValuel);
                    sp.premiums = new Array<Premium>();
                    _.each(premiumValuel.premiums, (premiumValue: any) => 
                        let premium: Premium = new Premium();
                        premium.setPremium(premiumValue);
                        sp.premiums.push(premium);
                    );
                    this.surpremiums.push(sp);
                );
            

            console.log(this.surpremiums);
        

        if (result.data && result.data.premiumTable && result.data.premiumTable.messageList && result.data.premiumTable.messageList.messages && result.data.premiumTable.messageList.messages.length > 0) 
            _.each(result.data.premiumTable.messageList.messages, (message: any) => 
                let messageType: any = MessageType[message.messageLevel.toString()];
                this.messages.push(new Message(messageType, "premiums", message.messageContent, this.premiums[i]));
            );

        

    , (err: any) => 
        this.premiums[i] = null;
        this.surpremiums = null;
        if (err && err.data && err.data.modelState) 
            for (var key in err.data.modelState) 
                var model = err.data.modelState[key];
                _.each(model, (state: string) => 
                    this.$log.debug(OfferControllerPrefix, "Calculation failed: " + state);
                );
            
        

        this.messages.push(new Message(MessageType.SVR_ERROR, "premiumCalculationParams", this.jsTranslations.getTranslation(Constants.DEFAULT_ERROR_NL), this.policy));
    );


public calculatePremiums(policy: Policy, selectedCoverageIndex : number): any 
    var uri = this.uriService.buildURI("Policy/Calculate");
    var data = 
        'policy': policy,
        'selectedCoverageIndex': selectedCoverageIndex
    ;
    return this.$http.post<any>(uri, data);

如何解决这个问题?

【问题讨论】:

您正在尝试更新已更新的Policy。你需要检查你的代码而不是那样做。 M1M2 在哪里? calculatePremiums 里面的 POST 是什么?是M1 还是M2 是的,http post调用之后,有很多方法在运行。举例来说,假设后端服务器有两个方法M1()和M2()。 在问题中,有一个函数返回一个承诺。另外两个函数返回void。如果您打算链接它们,这两个函数需要返回承诺。 Promise 的 .then 方法返回一个新的 Promise,该 Promise 产生返回给它的值。 【参考方案1】:

要链接两个异步操作,请将值返回到它们的.then 方法:

function M1(data) 
    return $http.post(url1, data);


function M2(data) 
    return $http.post(url2, data);

像这样链接两个函数:

function M1M2 () 

    var promise = M1(data);

    var promise2 = promise.then(function(data) 
       var data2 = fn(data);
       var m2Promise = M2(data2);
       return m2Promise;
    );

    return promise2;

因为调用 Promise 的 .then 方法会返回一个新的派生 Promise,所以很容易创建一个 Promise 链。

可以创建任意长度的链,并且由于可以使用另一个 Promise 来解决 Promise(这将进一步推迟其解决方案),因此可以在链中的任何点暂停/延迟解决 Promise。这使得实现强大的 API 成为可能。

有关详细信息,请参阅AngularJS $q Service API Reference - chaining promises。

【讨论】:

以上是关于在 for 循环打字稿和休眠死锁中调用异步函数的主要内容,如果未能解决你的问题,请参考以下文章

在for循环中调用异步函数

在 JavaScript 的 for 循环中调用异步函数

Vue Prop 未定义,和/或不能在 v-for 上使用。使用打字稿和装饰器

在 for 循环中的异步函数调用中有条件地执行回调

打字稿和传播运算符?

打字稿和多个类