AJAX -- 多个并发请求:延迟 AJAX 执行,直到某些调用完成

AJAX -- Multiple concurrent requests: Delay AJAX execution until certain calls have completed

本文关键字:AJAX 调用 执行 并发 请求 延迟      更新时间:2023-09-26

我目前正在开发一个基于网络的时间跟踪软件。我正在用grails开发,但这个问题只与javascript和异步请求有关。

时间跟踪工具应使用户能够为当月选择一天为每天创建一个或多个活动保存一整天。每个活动都必须分配给一个项目和一个合同。

选择"保存"后,将部分日期保存到数据库中,计算小时数,并在页面底部更新表格,显示用户每月工作时间的概述。

现在谈谈我的问题:可能有很多 AJAX 请求。患者用户可能只单击一次"创建活动"按钮,然后等待它被创建。然而,其他人可能会继续点击,直到发生某些事情。

这里的主要问题是更新视图,尽管我也认识到由于并发数据库事务而导致的一些失败调用(尤其是在按顺序选择"保存"和"删除"时(。关于该问题的任何反馈 - 请求不"等待"同一行再次准备就绪 - 也将受到赞赏,但这不是我的问题。

我有一个updateTemplate(data, day)函数,在我的任何一个函数saveRecord()deleteRecord()pasteRecords()makeEditable()(撤消保存(中,各个 ajax 调用的成功都会调用它。下面是 jquery 中的 AJAX 调用示例:

$.ajax({
    type: "POST",
    url: "${g.createLink(controller:"controller", action:"action")}",
    data: requestJson,
    contentType:"application/json; charset=utf-8",  
    async: true,
    success: function(data, textstatus) {updateTemplate(data["template"], tag); updateTable(data["table"]);},
}); 

在控制器操作中,JSON 对象呈现为响应,其中包含键templatetable。每个键都有一个模板,使用 g.render 呈现为分配给它的字符串。

现在,当我在非常短的时间间隔内反复单击create时会发生什么,由于异步调用,一些create(或其他(操作会同时执行。问题是updateTemplate只是从响应中呈现数据;要呈现的数据在"create控制器"操作中收集。但是"最后一个"请求操作仅查找自己创建的对象。我认为这是因为create操作是同时运行的

我认为我要么过于复杂,要么在使用动态刷新的页面时做了一些本质上错误的事情。我发现唯一有帮助的是同步调用,它有效,但用户体验很糟糕。我有什么选择来完成这项工作?真的是这样还是我只是在寻找错误的方法?我怎样才能使这一切更加健壮,以便不耐烦的用户无法破解我的代码?

*********编辑:********

我知道我可以阻止按钮或键盘快捷键,使用同步呼叫或类似的东西来避免这些问题。但是,我想知道是否有可能通过提交多个 AJAX 请求来解决它。因此,用户应该能够继续添加新活动,尽管它们不会立即出现。无论如何,都有一个用于反馈的微调器。我只是想以某种方式确保在触发"最后一个"AJAX 请求之前,数据库是最新的,以便控制器操作将使用具有正确对象的最新 gsp 模板进行响应

在这个 Stackoverflow 答案的帮助下,我找到了一种方法来确保 ajax 调用 - 在最后执行的 javascript 函数中 - 始终以最新的模型响应。基本上,如果之前已启动"关键"AJAX 请求但尚未完成,我将包含 AJAX 调用的 javascript 函数放在等待队列中。

为此,我定义了函数doCallAjaxBusyAwareFunction(callable),该函数在执行callable函数之前检查全局变量Global.busy是否为"true"。如果为 true,该函数将再次执行,直到Global.busy false,以最终执行该函数 - 从 DOM 收集数据 - 并触发 AJAX 请求。

全局变量的定义:

var Global = {
    ajaxIsBusy = false//,
    //additional Global scope variables
};

函数的定义doCallAjaxBusyAwareFunction

function doCallAjaxBusyAwareFunction(callable) {
        if(Global.busy == true){
           console.log("Global.busy = " + Global.busy + ". Timout set! Try again in 100ms!!");  
           setTimeout(function(){doCallAjaxBusyAwareFunction(callable);}, 100);
        }     
        else{                
            console.log("Global.busy = " + Global.busy + ". Call function!!");   
            callable();             
        }
    }

为了将包含 ajax 的函数标记为关键函数,我让它在一开始就设置Global.busy = true,并在 AJAX 上完成Global.busy = false。调用示例:

function xyz (){
    Global.busy = true;
    //collect ajax request parameters from DOM
    $.ajax({
        //desired ajax settings
        complete: function(data, status){ Global.busy = false; }
    }

由于Global.busy在一开始就设置为 true,因此 DOM 无法作 - 例如,在函数xyz收集 DOM 数据时通过 delete s。但是当函数被执行时,在 ajax 调用完成之前仍有Global.busy === true

从"忙碌感知"函数触发 ajax 调用:

doCallAjaxBusyAwareFunction(function(){
    //collect DOM data
    $.ajax({/*AJAX settings*/});
});

....或者从"忙碌感知"函数触发 ajax 调用,该函数本身也被标记为关键(基本上是我主要使用它的目的(:

doCallAjaxBusyAwareFunction(function(){
    Global.busy = true;
    //collect DOM data
    $.ajax({
        //AJAX SETTINGS
        complete: function(data, status){ Global.busy = false; }
    });
});

欢迎反馈和其他选项,特别是如果这种方法是不好的做法。我真的希望有人找到这篇文章并对其进行评估,因为我不知道是否应该这样做。我暂时不回答这个问题。