异步JS

最近忙于工作项目,很久没有写博客了,然而博客还是得写,帮助很大。三言两语也好,以后尽量抽空多写写。欢迎指正交流。

第一次接触到异步的概念来自于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/

原文地址:https://www.cnblogs.com/coiorz/p/4678515.html