理解javascript异步编程(2)

function f1(callback){ setTimeout(function () {    // f1的大量耗时任务代码并的到三个结果i,l,you.    console.log("this is function1");    var i = "i", l = "love", y = "you"; if (callback && typeof(callback) === "function") { callback(i,l,y); } }, 50); } function f2(a, b, c) { alert(a + " " + b + " " + c); console.log("this is function2"); } function f3(){console.log("this is function3");} f1(f2); f3();

运行结果:

this is function3 this is function1 i love you this is function2

采用这种方式,我们把同步操作变成了异步操作,f1不会堵塞程序运行,相当于先执行程序的主要逻辑,将耗时的操作推迟执行。
回调函数的优点是简单,轻量级(不需要额外的库)。缺点是各个部分之间高度耦合(Coupling),流程会很混乱,而且每个任务只能指定一个回调函数。某个操作需要经过多个非阻塞的IO操作,每一个结果都是通过回调,产生意大利面条式(spaghetti)的代码。

operation1(function(err, result) { operation2(function(err, result) { operation3(function(err, result) { operation4(function(err, result) { operation5(function(err, result) { // do something useful }) }) }) }) })

四、事件监听

另一种思路是采用事件驱动模式。任务的执行不取决于代码的顺序,而取决于某个事件是否发生。

// plain, non-jQuery version of hooking up an event handler var clickity = document.getElementById("clickity"); clickity.addEventListener("click", function (e) { //console log, since it's like ALL real world scenarios, amirite? console.log("Alas, someone is pressing my buttons…"); }); // the obligatory jQuery version $("#clickity").on("click", function (e) { console.log("Alas, someone is pressing my buttons…"); });

也可以自定义事件进行监听,关于自定义事件,属于另外一部分的内容。这种方法的优点是比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以"去耦合"(Decoupling),有利于实现模块化。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。

五、观察者模式

我们假定,存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe pattern),又称"观察者模式"(observer pattern)。

var pubsub = (function(){ var q = {} topics = {}, subUid = -1; //发布消息 q.publish = function(topic, args) { if(!topics[topic]) {return;} var subs = topics[topic], len = subs.length; while(len--) { subs[len].func(topic, args); } return this; }; //订阅事件 q.subscribe = function(topic, func) { topics[topic] = topics[topic] ? topics[topic] : []; var token = (++subUid).toString(); topics[topic].push({ token : token, func : func }); return token; }; return q; //取消订阅就不写了,遍历topics,然后通过保存前面返回token,删除指定元素 })(); //触发的事件 var f2 = function(topics, data) { console.log("logging:" + topics + ":" + data); console.log("this is function2"); } function f1(){  setTimeout(function () {       // f1的任务代码       console.log("this is function1"); //发布消息'done' pubsub .publish('done', 'hello world');     }, 1000); } pubsub.subscribe('done', f2); f1();

上面代码的运行结果为:

this is function1 logging:done:hello world this is function2

观察者模式的实现方法有很多种,也可以直接借用第三方库。这种方法的性质与"事件监听"类似(观察者模式和自定义事件非常相似),但是明显优于后者。观察者模式和事件监听一样具有良好的去耦性,并且有一个消息中心,通过对消息中心的处理,可以良好地监控程序运行。

六、Promises对象

Promises的概念是由CommonJS小组的成员在 Promises/A规范 中提出来的。Promises被逐渐用作一种管理异步操作回调的方法,但出于它们的设计,它们远比那个有用得多。Promise允许我们以同步的方式写代码,同时给予我们代码的异步执行。

function f1(){ var def = $.Deferred(); setTimeout(function () { // f1的任务代码 console.log("this is f1"); def.resolve(); }, 500); return def.promise(); } function f2(){ console.log("this is f2"); } f1().then(f2);

上面代码的运行结果为:

this is f1 this is f2

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wgwzgj.html