JavaScript在异步处理上十分方便,最一开始用到异步是JavaScript封装框架jQuery来请求后台的代码
$.post(url,param,callback)
而这种方式需要提供回调函数
但是回调函数可能会出现这样的窘境:
一个回调的经典场景:nodejs中mongoDB的查询使用
var p_client = new Db('integration_tests_20', new Server("127.0.0.1", 27017, {}), {'pk':CustomPKFactory}); p_client.open(function(err, p_client) { p_client.dropDatabase(function(err, done) { p_client.createCollection('test_custom_key', function(err, collection) { collection.insert({'a':1}, function(err, docs) { collection.find({'_id':new ObjectID("aaaaaaaaaaaa")}, function(err, cursor) { cursor.toArray(function(err, items) { test.assertEquals(1, items.length); // Let's close the db p_client.close(); }); }); }); }); }); });
为了解决多层异步不利于理解和调错的问题,ES6引入了新的对象,Promise
mozilla官方对它的定义是:
Promise
对象用于异步(asynchronous)计算.。一个Promise对象代表着一个还未完成,但预期将来会完成的操作在我看来Promise是一个包含自执行器的状态机
我们模拟一下Promise的实现
//全局宏定义 var PENDING = 0; var FULFILLED = 1; var REJECTED = 2; //Promise构造函数 function Promise(fn){ var self = this; self.state = PENDING;//初始化状态 self.value = null;//存储异步结果的对象变量 self.handlers = [];//存储回调函数,这里没保存失败回调函数,因为这是一个dome //异步任务成功后处理,这不是回调函数 function fulfill(result){ if(self.state === PENDING){ self.state = FULFILLED; self.value = result; for(var i=0;i<self.handlers.length;i++){ self.handlers[i](result); } } } //异步任务失败后的处理, function reject(err){ if(self.state === PENDING){ self.state = REJECTED; self.value = err; } } fn&&fn(fulfill,reject); }; //使用then方法添加回调函数,把这次回调函数return的结果当做return的promise的resolve的参数 Promise.prototype.then = function(onResolved, onRejected){ var self = this; return new Promise(function(resolve, reject){ var onResolvedFade = function(val){ var ret = onResolved?onResolved(val):val;//这一步主要是then方法中传入的成功回调函数通过return来进行链式传递结果参数 if(Promise.isPromise(ret)){//回调函数返回值也是promise的时候 ret.then(function(val){ resolve(val); }); } else{ resolve(ret); } }; var onRejectedFade = function(val){ var ret = onRejected?onRejected(val):val; reject(ret); }; self.handlers.push(onResolvedFade); if(self._status === FULFILLED){ onResolvedFade(self._value); } if(self._status === REJECTED){ onRejectedFade(self._value); } }); }
使用如下:
function p(value){ var pms = new Promise(function(resolve, reject){ setTimeout(function(){ resolve(value);; }, 1000); }); return pms; } p(1).then(function(result){ console.log('the result is ',result);//the result is 2 return result; }).then(function(result){ console.log(++result);//2 });
成功进入resolve参数,失败则进入reject函数
ES6中提供的Promise还有捕获异常的catch组件
更进一步,ES6中实现了C#中存在的async await 关键字,如下:
其中async对修饰函数做了一个Promise封装
function timeout(ms){ return new Promise((resolve)=>{ setTimeout(resolve,ms); }) } async function asyncPrint(value,ms){ await timeout(ms); console.log(value); } asyncPrint('hello world',1000); console.log('end');
APM
C#中对应的叫做APM( Asynchronous Programming Model)
基于回调的异步实现,类似的实现BeginInvoke异步方法的类
java中的异步回调稍微麻烦一些,可以自己实现
public class CallBackTest extends AbstractCallBack { public CallBackTest(CallHandler handler) { super(handler); } public static void main(String[] args) { CallBackTest callTest = new CallBackTest(new CallHandler() { @Override public void handler(String param) { System.out.println("处理参数:" + param); } }); callTest.start("参数1"); } @Override void after() { System.out.println("回调处理"); } } //异步处理 abstract class AbstractCallBack { private CallHandler callHandler; public final void start(final String param) { new Thread(new Runnable() { @Override public void run() { callHandler.handler(param); after(); } }).start(); } public AbstractCallBack(CallHandler handler) { this.callHandler = handler; } abstract void after(); } //回调函数接口 interface CallHandler { public void handler(String param); }
TAP 基于任务的异步模式,Task-based Asynchronous Pattern
Java并发包中已经有相应的实现了,我们可以用 FutureTask达到相应的效果:
public class futureTaskTest { public static void main(String[] args) { ExecutorService executor = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++) { Callable<String> c = new Task(); MyFuture ft = new MyFuture(c); executor.submit(ft); } executor.shutdown(); } } class MyFuture extends FutureTask<String> { public MyFuture(Callable<String> callable) { super(callable); } public void done() { System.out.println(" 线程执行完毕!~"); } } class Task implements Callable<String> { @Override public String call() throws Exception { // TODO Auto-generated method stub Thread.sleep(1000); System.out.println(" 执行中"); return Thread.currentThread().getName(); } }
Event-based Asynchronous Pattern基于事件的异步
参考我先前的一篇文章,基于观察者模式实现java的事件:http://www.cnblogs.com/wanglao/p/5305076.html
将其异步化,改变事件监听者(事件处理),然后在事件源的触发器中增加线程控制:
abstract class Handler implements EventListener, Runnable { EventState state; public Handler(EventState state) { this.state = state; } public void doHandler() { System.out.println("handler1 执行了,现在状态是:" + state); } public void run() { doHandler(); } }
//事件执行 protected void notifies(EventState sate){ if ( eventListeners.size()>0) { for (Handler handler : eventListeners) { new Thread(handler).start(); } } }
另外,一些设计模式也是天生适合异步多线程环境,比如生产者-消费模式。
参考:http://www.cnblogs.com/zhaopei/p/async_one.html