18.5. 请求排队

先来看一段代码。页面代码和LiteBean代码分别如下:

    <w:form>
      <w:button label="模拟点击另外两个按钮" onclick="t1Jsvar.fireEvent('click');t2Jsvar.fireEvent('click');" />
      <w:button id="t1" label="按钮1" jsvar="t1Jsvar" />
      <w:button id="t2" label="按钮2" jsvar="t2Jsvar" />
    </w:form>
    @Action
    public void t1() {
        System.out.println(1);
    }

    @Action
    public void t2() {
        System.out.println(2);
    }

期望的目标是:点击第一个按钮,会模拟点击第二个和第三个按钮,发送两个Ajax请求,从而在控制台打印出1和2。

而实际的效果是:控制台只是打印了1,并没有打印出2。无论重复点击按钮多少次,后台结果都是一样。

在OperaMasks 2.3及之前的版本中,在发送Ajax请求时,如果同个Form中还有尚未完成的请求,则后续的请求会被直接抛弃。上面的代码中两个请求刚好是同一Form中的,而且间隔非常短,则第2个请求会被抛弃。而且抛弃请求后用户并不知道。

要想实现请求排队的功能,需要用Java代码或JavaScript代码将并行的请求变成串行的。有两种办法:

第一种方法的优点是请求的延迟是在客户端用JavaScript实现的,不需要与服务器端交互,缺点是要延迟的毫秒数不易确定,定得太大,则对于网络好的用户需要额外浪费等待时间,定得太小则达不到延迟发送请求的目的。第二种方法的优点是不需要考虑网络及请求执行时间,而且并不会增加与服务器端交互的次数(两种方法都是交互3次),缺点是两个按钮在代码上与调用顺序上产生了藕合,不适用于大多数的场景。

从OperaMasks 3.0版本开始,w:form构件提供了三个属性:Boolean queueRequest(是否对form中发起的Ajax请求进行排队)、Integer timeout(form中发起的Ajax请求排队的超时时间)、String ontimeout(form中发起的Ajax请求超时后的执行的JavaScript代码)以支持请求排队,还可以由用户设置请求超时时间(默认为无穷大)及请求超时的回调js函数。请求排队时Ajax请求的处理流程如下图。

请求排队时Ajax请求的处理流程图

图 18.1. 请求排队时Ajax请求的处理流程图


从OperaMasks 3.0版本开始w:form会默认进行请求排队(queueRequest默认为true),要设置请求超时时间及超时回调函数,代码如下:

   <w:form timeout="2000" ontimeout="alert('请求超时了!');">
      <w:button label="模拟点击另外两个按钮" onclick="t1Jsvar.fireEvent('click');t2Jsvar.fireEvent('click');" />
      <w:button id="t1" label="按钮1" jsvar="t1Jsvar" />
      <w:button id="t2" label="按钮2" jsvar="t2Jsvar" />
   </w:form>

点击第一个按钮,会用js模拟点击第二个和第三个按钮,发送2个Ajax请求,请求会进行排队(第二个按钮的请求在前,第三个按钮的请求在后,第一个按钮的请求在最后),如果某个请求在2000毫秒后还得不到处理,则会抛弃访请求,并执行ontimeout中的js代码,弹出alert提示框。

由于w:form默认是进行请求排队的,所以要禁用请求排队,只需要将w:form的queueRequest属性设为false即可。