先来看一段代码。页面代码和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代码将并行的请求变成串行的。有两种办法:
方法1:用JavaScript代码让后面的请求延迟发送
只需要将上面页面中的代码改为:
<w:form>
<w:button label="模拟点击另外两个按钮"
onclick="t1Jsvar.fireEvent('click');window.setTimeout(function(){t2Jsvar.fireEvent('click');},1000);" />
<w:button id="t1" label="按钮1" jsvar="t1Jsvar" />
<w:button id="t2" label="按钮2" jsvar="t2Jsvar" />
</w:form>即可。意思是让第二个请求延迟1000毫秒再发送。这个时间要视请求的复杂度和网络情况而定。如果网络速度较慢或第一个请求要执行很长时间,则要加大这个延迟时间。
方法2:用Java代码让后面的请求延迟发送
就是只提交第一个请求,在第一个请求的响应中加入代码提交第二个请求,从而达到延迟发送第二个请求的目的。代码如下:
<w:form>
<w:button label="模拟点击另外两个按钮" onclick="t1Jsvar.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);
Browser.execClientScript("t2Jsvar.fireEvent('click');");
}
@Action
public void t2() {
System.out.println(2);
}第一种方法的优点是请求的延迟是在客户端用JavaScript实现的,不需要与服务器端交互,缺点是要延迟的毫秒数不易确定,定得太大,则对于网络好的用户需要额外浪费等待时间,定得太小则达不到延迟发送请求的目的。第二种方法的优点是不需要考虑网络及请求执行时间,而且并不会增加与服务器端交互的次数(两种方法都是交互3次),缺点是两个按钮在代码上与调用顺序上产生了藕合,不适用于大多数的场景。
从OperaMasks 3.0版本开始,w:form构件提供了三个属性:Boolean queueRequest(是否对form中发起的Ajax请求进行排队)、Integer timeout(form中发起的Ajax请求排队的超时时间)、String ontimeout(form中发起的Ajax请求超时后的执行的JavaScript代码)以支持请求排队,还可以由用户设置请求超时时间(默认为无穷大)及请求超时的回调js函数。请求排队时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即可。