您的位置:首页 > Web前端 > JavaScript

extjs 循环执行多个异步请求时,参数和后台以及相关问题和衍生问题的处理

2016-10-24 10:51 295 查看
在Extjs中,异步请求的写法:

Ext.Ajax.request({
url: '***.action',
//async: false,
params: {
p1: v1,
p2: v2
...
},
success: function(response, options){
//TODO
}
});
其中,若想变成同步请求,只需要在配置项中添加async: false,默认true。
配置说明:

url,访问的请求地址;

params,参数对象,为请求提供的条件;

success,当请求执行成功后,会进入该回调方法。

说到这里,我们先来回忆一下什么是异步请求,简单来说就是不需要等待上一个请求的返回便可执行;简单的说,若发起了10次异步请求,且中间过程用时极短,那么我们可以看作这10次请求是一起访问目标地址的;

这里我用一个循环来举例说明异步(类似Java多线程)的一些问题和解决方法。

//5个不同对象(结构相同,内容不同)
var params = [obj1, obj2, obj3, obj4, obj5];
for(var i = 0; i < params.length; i++){
var param = params[i];
Ext.Ajax.request({
url: '?',
params: {
key: param.key,
fileName: param.fileName
},
success: function(response, options){
console.info(i);//标记1
append(param.config);//标记2
}
});
}
问题1:当循环结束,标记1处输出的值分别是多少?

问题2:该方法传递的config对象是否是同一对象?

你心中是否有了答案?

首先第一个问题,答案是一共输出了5次5,有没有答对?我想应该没有答对是吧,那么为什么是这样一种输出结果,而不是0,1,2,3,4,原理则稍后再说明。

再来看第二个问题,答案是同一个对象,是不是出乎意料?你说,param对象不是循环得到的吗,为什么会是同一对象,这里原理和第一问是一样的。

现在我就来说下为什么是这样一种结果。首先,我们要注意到这是一个异步请求,它不会像同步方法一样非要等到返回结果(这里的返回结果就是success回调函数,当请求正确执行完成后就会调用该回调函数,告诉请求执行完了)才会进入下次循环,而是直接把所有循环次数都走完了,说到这里是不是开始有点明白了?这里我再说两个相关数据:循环时间,请求执行时间。假设这里的循环执行完毕只需要100ms,而每次请求的执行时间是300ms,那么这意味着当请求执行结束进入success函数时,我们的i变量已经连循环的退出判定都已经执行完了,所以此时的变量i就是5,同样的道理,param对象也是一样,所以执行结果就是之前提到的那样。(有个群友很好的解释了这个问题:在进入回调之前,老五已经出发了)

那么新问题来了,怎么才能够输出0,1,2,3,4以及得到不同的参数对象呢?

方法1:同步,即把async: false写上即可,但这样就变成了同步了;

方法2:将这些局部变量封装到请求中。

不知道你有没有注意到回调函数success中的2个参数options和response?他们是什么呢,options就是请求的整个对象(即request({...})红色部分),response就是后台响应对象,包括返回结果。

既然取外部的局部变量不行,那直接从请求对象中取值总不会错了吧。你可能会问,这样难道就不会是得到最后一次请求的内容?如果你知道类封装和类实例就应该明白了,

由于每次请求传递的都是一个新的对象(类实例),并且在请求执行完成后反馈给options,当我们从options对象中取出自己定义的参数时,则和传入时保持一致,就不会出现之前的问题了。

举个自定义的例子:

Ext.Ajax.request({
url: '?',
//名字自定,在用的时候知道就好,但不要和其他配置名重名
definedParams: {
?
},
success: function(response, options){
//得到自定义参数
var ps = options.definedParams;
}
});


这里,我再提一点,我测试使用的是Struts结合Spring,Struts默认是多例,而Spring默认是单例,用Spring管理创建Action实例对象,在多个异步请求同时访问这个Action时,会造成参数混乱(因为是单例),所以我把Spring也改成了多例,在bean的配置中添加属性scope="prototype"即可。

如果你使用的是servlet来做请求拦截的话,那就不用考虑了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐