【问题】
使用ExtJs处理批量数据时,使用for循环通过Ext Ajax调用后台,代码如下:
for(var i=0; i<params.length; i++){
Ext.Ajax.request({
url:this.url,
params:params[i],
method:'POST',
success:function(response) {
},
scope:this
});
}
因为Ajax是异步处理的,导致后台接收到的数据无法保持正常的次序,后台的逻辑就会出现错乱。
【思路】
最简单的思路就是将异步调用转换为同步调用,但找了很多办法,Ext.Ajax.request要支持同步发送需要修改核心代码,这个才目前的产品上是不允许的;其它的同步调用的方法暂时没有找到,于是放弃了此思路;
另外的思路就是Ext.Ajax.request真正处理结束后才执行下一次调用:
1. 此时Ext.Ajax.request的success回调是不行的,因为只在成功的时候才会执行此回调,因此需要使用callback回调方法;
2. 如果使用for循环,不会等到Ext.Ajax.request的回调,就进行下一个循环了,所以for循环不行;如果在Ext.Ajax.request没有回调前,在for中写一个等待的逻辑,例如while(isOk);显然也会有性能等诸多问题;
3. 如何才能解决2的问题,最好的办法是使用递归模拟for循环;
【执行】
添加一个递归函数:
batchProcess: function(index, length, params){
if(index >= length){
alert('处理结束');
return;
}else{
Ext.Ajax.request({
url:this.url,
params:params[index],
method:'POST',
success:function(response) {
batchProcess(++index, length, params);
},
scope:this
});
}
}
然后使用batchProcess(0, params.length, params);进行调用。
至此我们发现问题得到解决,此外还发现另外一个好处就是,我们可以控制批量执行时从第几条数据开始执行,例如从第3条开始执行:batchProcess(2, params.length, params);
【扩展:使用Java模拟异步处理,并使用递归同步调用】
【1:使用线程模拟Ext.Ajax.request调用】
package sync;
/**
* 使用线程模拟异步处理逻辑
*
* @author 李文锴
* @since 2012-8-16 下午05:20:39
*
*/
public abstract class Asyn extends Thread {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
onSuccess();
}
/**
* 当异步处理成功时的回调
*
* @Description:
* @author 李文锴
* @since:2012-8-16 下午05:21:32
*/
public abstract void onSuccess();
}
【2:使用Java模拟for循环调用异步逻辑】
package sync;
/**
* for循环执行异步逻辑
*
* @author 李文锴
* @since 2012-8-17 上午08:46:07
*
*/
public class AsynFor {
public static void main(String[] args) {
String[] params = { "aaa", "bbb", "ccc", "ddd" };
new AsynFor().asynProcess(params);
}
/**
* 模拟对于异步方法执行for循环
*
* @Description:
* @param params
* @author 李文锴
* @since:2012-8-17 上午08:32:22
*/
public void asynProcess(String[] params) {
for (int i = 0; i < params.length; i++) {
doBusinessProcess(i, params[i]);
}
}
/**
* 异步调用执行业务逻辑
*
* @Description:
* @param index
* @author 李文锴
* @since:2012-8-17 上午08:46:45
*/
private void doBusinessProcess(final int index, final String data) {
new Asyn() {
@Override
public void onSuccess() {
System.out.println("业务执行:" + index);
System.out.println(index + " : 业务完成后输出 => " + data + "\n");
}
}.start();
}
}
执行后输出如下:
业务执行:2
2 : 业务完成后输出 => ccc
业务执行:0
0 : 业务完成后输出 => aaa
业务执行:1
1 : 业务完成后输出 => bbb
业务执行:3
3 : 业务完成后输出 => ddd
我们发现并没有按照正常的次序执行,通过上面的Java代码复现了在ExtJs中会遇到的问题
【3:使用Java模拟递归处理批量异步逻辑同步执行问题】
package sync;
/**
* 使用递归模拟for循环处理业务逻辑,同步执行
*
* @author 李文锴
* @since 2012-8-17 上午08:47:33
*
*/
public class SyncFor {
public static void main(String[] args) {
String[] params = { "aaa", "bbb", "ccc", "ddd" };
new SyncFor().syncProcess(0, params.length, params);
}
/**
* 使用递归进行同步输出
*
* @Description:
* @param index
* @param length
* @param params
* @author 李文锴
* @since:2012-8-17 上午08:29:10
*/
public void syncProcess(final int index, final int length, final String[] params) {
if (index >= length) {
return;
} else {
new Asyn() {
@Override
public void onSuccess() {
System.out.println("业务执行:" + index);
System.out.println(index + " : 业务完成后输出 => " + params[index] + "\n");
syncProcess(index + 1, length, params);
}
}.start();
}
}
}
执行输出如下:
业务执行:0
0 : 业务完成后输出 => aaa
业务执行:1
1 : 业务完成后输出 => bbb
业务执行:2
2 : 业务完成后输出 => ccc
业务执行:3
3 : 业务完成后输出 => ddd
结果按照我们期望的异步逻辑同步处理了。
【延伸】
1. “同步、异步、线程、并发、锁、队列、点对点、发布订阅、主题、消息”这些都是同一个领域的相关概念,融汇贯通,其本质是一样的。
2. 要分清楚什么时候需要使用异步、什么时候需要使用同步。如果不存在一段代码调用后立刻执行后面的逻辑(不需要等后面处理结束),还是建议使用同步处理,这样可能用户体验会有写问题,但产品质量不会存在问题。
3. 用户体验和产品质量是个两难的问题,需要平衡。
分享到:
相关推荐
非递归算法,也称为迭代算法,通常使用堆栈或队列来模拟递归行为,而避免了函数的多次调用。在遍历文件系统时,它会将目录添加到数据结构中,然后依次处理这些目录,直到找到目标文件或遍历完所有目录。非递归算法在...
在 Java 中,使用递归算法可以将树形结构数据处理成 JSON 格式。在这个示例代码中,我们使用了 json-lib.jar 包将 List 序列化成 JSON。首先,我们需要定义一个 TreeBuilder 类,该类包含了构建树形结构的方法。 ...
递归算法是把问题转化为规模缩小了的同类问题的子问题,然后递归调用函数(或过程)来表示问题的解。递归的效率一般不高,但是递归比较符合人类的思维方式。一般而言非递归算法更有效;但很多时候递归算法容易实现,...
递归算法与循环算法的分析 递归算法是指在程序设计中,在调用一个函数...8. 递归算法和循环算法在二分查找算法中的应用:递归算法和循环算法的时间复杂度都为 O(logn),但是循环算法的空间复杂度较低,且更容易实现。
递归步骤定义了如何将大问题转化为小问题的过程,并且最终会归结到基本情况。递归步骤需要精心设计以确保每一次递归都能朝着终止条件迈进。 #### 非递归算法 非递归算法不直接调用自身,而是通过循环等其他方式来...
2. **递归情况(Recursive Case)**:这是函数调用自身的部分,将原问题转化为更小的子问题。每次递归调用都会使问题规模减小,直到达到基础情况。 递归在.NET中可以用于各种应用,例如: - **树形结构遍历**:如...
### Java编写的递归算法的经典事例:全排列输出 #### 概述 本文将详细介绍一个用Java编写的递归算法实例,该实例用于实现字符数组的所有可能全排列。通过这个例子,我们可以深入理解递归的基本概念、工作原理以及...
7. **动态规划与记忆化**:为了优化递归算法,可以采用动态规划的思想,将已经计算过的子问题结果存储起来,避免重复计算,这种方法称为记忆化搜索。 8. **递归与分治策略**:递归往往是分治算法的实现方式,如快速...
2. **递归步骤(Recursive Step)**:定义如何将问题分解为更小的问题,并调用自身解决这些子问题。 #### 递归与循环的区别 虽然递归和循环都可以用来重复执行某段代码,但它们之间存在明显的区别: - **递归**:...
当追求更高的效率时,可以将递归算法转换为基于栈的非递归算法,甚至进一步优化为仅使用循环的非递归算法。然而,在一些更复杂的情况下,虽然可以转换为基于栈的非递归算法,但无法完全消除栈的使用。此外,有些递归...
3. **编程实践**:指导学生使用编程语言(如Python、Java等)实现递归算法,通过实际操作加深理解。 4. **互动游戏**:设计一些有趣的互动游戏,如课堂导入中提到的礼物传递游戏,让学生在游戏中体验递归思想。 5. *...
3. **处理递归情况**:将原问题分解为较小的子问题,并调用自身解决。 4. **合并结果**:将所有子问题的结果组合成原问题的答案。 文档"Java递归算法.docx"可能包含了关于如何在实际代码中应用递归的例子,例如经典...
1、递归算法是一种直接或者间接调用自身函数或者方法的算法,就是将复杂问题不断分解为规模缩小的子问题,然后递归调用方法求解 2、递归思维是一种从下向上的思维方式,使用递归算法往往可以简化我们的代码,而且还...
Java递归算法是一种编程技术,它允许函数或方法在执行过程中调用自身。递归通常用于解决具有重复子问题的问题,通过将复杂问题分解成更小的子问题来简化处理。这种策略的关键在于存在一个终止条件,即所谓的递归基,...
合并排序是一种基于分治策略的高效排序算法,它将大问题分解为小问题来解决,然后将小问题的结果合并以得到最终的解决方案。这个过程既可以用递归方式实现,也可以用非递归方式实现。 首先,让我们来看看递归版本的...
递归多线程算法的实现,特别是使用Java这样的现代编程语言,为并行计算提供了一个强大的框架。通过对递归算法的多线程化,我们可以显著提高算法的执行速度和响应能力,尤其是在面对大规模数据集时。未来的研究方向...
递归算法通过将问题分解为规模较小的子问题来解决整个问题,具体实现如下: ```cpp void hanoi(int n, char one, char two, char three) { if (n == 1) move(one, three); else { hanoi(n-1, one, three, two); ...
- **手动模拟递归过程**:使用显式的数据结构(如栈)来保存递归调用的上下文,从而模拟递归调用的行为。 总之,递归算法是程序设计中一种非常强大的技术,它不仅可以帮助我们更简洁地解决问题,而且还能提高代码的...
首先,递归算法的核心在于它将大问题分解为小的相似子问题。在C++中,递归通常涉及函数调用,如下所示: ```cpp int factorial(int n) { if (n == 0 || n == 1) { return 1; } else { return n * factorial(n -...