`
sony-soft
  • 浏览: 1019691 次
文章分类
社区版块
存档分类
最新评论

使用递归算法将批量调用异步处理转化为同步调用,并使用Java模拟ExtJs异步处理同步化

 
阅读更多
【问题】

使用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. 用户体验和产品质量是个两难的问题,需要平衡。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics