最近忙于工作项目,很久没有写博客了,然而博客还是得写,帮助很大。三言两语也好,以后尽量抽空多写写。欢迎指正交流。
第一次接触到异步的概念来自于ajax,即页面向服务端发请求,不等待返回结果而继续向后执行,当结果返回时执行回调,回调函数执行的时机是不确定的,取决于服务端何时返回结果。相对的,同步就是指一直等到结果返回后才继续向后执行。
我理解中,JS中实现异步的方式有两种:回调和事件监听
一. 回调(callback)
最基本的回调方式,用一个简单的应用场景来阐述,假设我们要搜索数据,然后进行处理,最后显示结果,用异步来实现。在现实工作中这些函数会发出ajax请求并得到返回结果,现在我们就用setTimeout来简单模拟一下
1 function finder(records, callback) { 2 setTimeout(function() { 3 records.push(3, 4); 4 callback(records); 5 }, 1000); 6 } 7 8 function processer(records, callback) { 9 setTimeout(function() { 10 records.push(5, 6); 11 callback(records); 12 }, 1000); 13 }
1 finder([1, 2], function(records) { 2 processor(records, function(records) { 3 console.log(records); 4 }); 5 });
我们调用finder函数,传入了一个回调函数,在这个回调函数中我们又调用processor函数,给它传入另一个回调函数。起个名字来引用回调函数可以使代码更易读
1 function onFinderDone(records) { 2 processor(records, onProcessorDone); 3 } 4 5 function onProcessorDone(records) { 6 console.log(records); 7 } 8 9 finder([1, 2], onFinderDone);
这种方式简单好理解,但其最大的一个缺点是你只能传入一个回调函数。
二. 事件监听(listener)
这块用到了jQuery的一些方法,不必太在意,重点在于阐述道理
首先我们需要两个对象,一个负责搜索数据,一个负责处理数据
1 var finder = { 2 run: function(records) { 3 var self = this; 4 setTimeout(function() { 5 records.push(3, 4); 6 self.trigger('done', [records]); 7 }, 1000); 8 } 9 }; 10 11 var processor = { 12 run: function(records) { 13 var self = this; 14 setTimeout(function() { 15 records.push(5, 6); 16 self.trigger('done', [records]); 17 }, 1000); 18 } 19 };
与上例回调方式对比,我们把调用回调函数替换成了trigger方法,定义如下
1 var eventable = { 2 on: function(event, callback) { 3 $(this).on(event, callback); 4 }, 5 6 trigger: function(event, args) { 7 $(this).trigger(event, args); 8 } 9 };
让我们的finder和processor对象获得事件监听、发布的能力
1 $.extend(finder, eventable); 2 $.extend(processor, eventable);
执行
1 finder.on('done', function(event, records) { 2 processor.run(records); 3 }; 4 5 processor.on('done', function(event, records) { 6 console.log(records); 7 }; 8 9 finder.run([1, 2]);
这种模式最大的优点在于你可以指定任意多个事件处理函数
原文中这一块过于依赖jQuery库,这里我参考了martinfowler的事件聚合(Event Aggregator),(原文http://martinfowler.com/eaaDev/EventAggregator.html或参考汤姆大叔的深入理解javascript系列),有兴趣的同学可以看看
1 function Event(name) { 2 var handlers = []; 3 this.getName = function() { 4 return name; 5 }; 6 this.addHandler = function(handler) { 7 handlers.push(handler); 8 }; 9 this.removeHandler = function(handler) { 10 for (var i = 0; i < handlers.length; i++ ) { 11 if (handlers[i] == handler) { 12 handlers.splice(i , 1); 13 break; 14 } 15 } 16 }; 17 this.fire = function(eventArgs) { 18 for (var i = 0; i < handlers.length; i++ ) { 19 handlers[i](eventArgs); 20 } 21 }; 22 } 23 24 function EventAggregator() { 25 var events = []; 26 function getEvent(eventName) { 27 return $.grep(events, function(event) { 28 return event.getName() == eventName; 29 })[0]; 30 } 31 this.subscribe = function(eventName, handler) { 32 var event = getEvent(eventName); 33 if (!event) { 34 event = new Event(eventName); 35 events.push(event); 36 } 37 event.addHandler(handler); 38 }; 39 this.publish = function(eventName, eventArgs) { 40 var event = getEvent(eventName); 41 if(!event) { 42 event = new Event(eventName); 43 events.push(event); 44 } 45 event.fire(eventArgs); 46 }; 47 }
译自:http://sporto.github.io/blog/2012/12/09/callbacks-listeners-promises/