var fromLatLng, toLatLng; var routeDone = function( e ){ console.log( "ANNNND FINALLY here's the directions..." ); // do something with e }; var toAddressDone = function( results, status ) { if ( status == "OK" ) { toLatLng = results[0].geometry.location; map.getRoutes({ origin: [ fromLatLng.lat(), fromLatLng.lng() ], destination: [ toLatLng.lat(), toLatLng.lng() ], travelMode: "driving", unitSystem: "imperial", callback: routeDone }); } }; var fromAddressDone = function( results, status ) { if ( status == "OK" ) { fromLatLng = results[0].geometry.location; GMaps.geocode({ address: toAddress, callback: toAddressDone }); } }; GMaps.geocode({ address: fromAddress, callback: fromAddressDone });
此外, async.js 库可以帮助我们处理多重Ajax requests/responses. 例如:
async.parallel([ function( done ) { GMaps.geocode({ address: toAddress, callback: function( result ) { done( null, result ); } }); }, function( done ) { GMaps.geocode({ address: fromAddress, callback: function( result ) { done( null, result ); } }); } ], function( errors, results ) { getRoute( results[0], results[1] ); });
这段代码执行两个异步函数,每个函数都接收一个名为"done"的回调函数并在函数结束的时候调用它。当两个"done"回调函数结束后,parallel函数的回调函数被调用并执行或处理这两个异步函数产生的结果或错误。
Promises模型
引自 CommonJS/A:
promise表示一个操作独立完成后返回的最终结果。
有很多库都包含了promise模型,其中jQuery已经有了一个可使用且很出色的promise API。jQuery在1.5版本引入了Deferred对象,并可以在返回promise的函数中使用jQuery.Deferred的构造结果。而返回promise的函数则用于执行某种异步操作并解决完成后的延迟。
var geocode = function( address ) { var dfd = new $.Deferred(); GMaps.geocode({ address: address, callback: function( response, status ) { return dfd.resolve( response ); } }); return dfd.promise(); }; var getRoute = function( fromLatLng, toLatLng ) { var dfd = new $.Deferred(); map.getRoutes({ origin: [ fromLatLng.lat(), fromLatLng.lng() ], destination: [ toLatLng.lat(), toLatLng.lng() ], travelMode: "driving", unitSystem: "imperial", callback: function( e ) { return dfd.resolve( e ); } }); return dfd.promise(); }; var doSomethingCoolWithDirections = function( route ) { // do something with route }; $.when( geocode( fromAddress ), geocode( toAddress ) ). then(function( fromLatLng, toLatLng ) { getRoute( fromLatLng, toLatLng ).then( doSomethingCoolWithDirections ); });
这允许你执行两个异步函数后,等待它们的结果,之后再用先前两个调用的结果来执行另外一个函数。
promise表示一个操作独立完成后返回的最终结果。
在这段代码里,geocode方法执行了两次并返回了一个promise。异步函数之后执行,并在其回调里调用了resolve。然后,一旦两次调用resolve完成,then将会执行,其接收了之前两次调用geocode的返回结果。结果之后被传入getRoute,此方法也返回一个promise。最终,当getRoute的promise解决后,doSomethingCoolWithDirections回调就执行了。
事件
事件是另一种当异步回调完成处理后的通讯方式。一个对象可以成为发射器并派发事件,而另外的对象则监听这些事件。这种类型的事件处理方式称之为 观察者模式 。 backbone.js 库在withBackbone.Events中就创建了这样的功能模块。
var SomeModel = Backbone.Model.extend({ url: "/someurl" }); var SomeView = Backbone.View.extend({ initialize: function() { this.model.on( "reset", this.render, this ); this.model.fetch(); }, render: function( data ) { // do something with data } }); var view = new SomeView({ model: new SomeModel() });
还有其他用于发射事件的混合例子和函数库,例如 jQuery Event Emitter , EventEmitter , monologue.js ,以及node.js内建的 EventEmitter 模块。
事件循环是一个回调函数的队列。
一个类似的派发消息的方式称为 中介者模式 , postal.js 库中用的即是这种方式。在中介者模式,有一个用于所有对象监听和派发事件的中间人。在这种模式下,一个对象不与另外的对象产生直接联系,从而使得对象间都互相分离。