分享

探索Javascript异步编程(2)

 集微笔记 2014-05-26

如果doA失败,它的Promise会被拒绝,处理链上的下一个onRejected会被调用,在这个例子中就是匿名函数function(error){}。比起原始的回调方式,不需要在每一步都对异常进行处理。这生了不少事。

以上只是对于Promise概念的简单陈述,Promise拥有许多不同规范建议(A,A+,B,KISS,C,D等),名字(Future,Promise,Defer),和开源实现。大家可以参考一下的这些链接。


如果你有选择困难综合症,面对这么多的开源库不知道如何决断,先不要急,这还只是一部分,还有一些库没有或者不完全采用Promise的概念

Non-Promise

下面列出了其它的一些开源的库,也可以帮助解决Javascript中异步编程所遇到的诸多问题,它们的解决方案各不相同,我这里就不一一介绍了。大家有兴趣可以去看看或者试用一下。

Non-3rd Party

其实,为了解决Javascript异步编程带来的问题,不一定非要使用Promise或者其它的开源库,这些库提供了很好的模式,但是你也可以通过有针对性的设计来解决。

比如,对于层层回调的模式,可以利用消息机制来改写,假定你的系统中已经实现了消息机制,你的code可以写成这样:

  1. eventbus.on("init"function(){  
  2.     operationA(function(err,result){  
  3.         eventbus.dispatch("ACompleted");  
  4.     });  
  5. });  
  6.  
  7. eventbus.on("ACompleted"function(){  
  8.     operationB(function(err,result){  
  9.         eventbus.dispatch("BCompleted");  
  10.     });  
  11. });  
  12.  
  13. eventbus.on("BCompleted"function(){  
  14.     operationC(function(err,result){  
  15.         eventbus.dispatch("CCompleted");  
  16.     });  
  17. });  
  18.  
  19. eventbus.on("CCompleted"function(){  
  20.     // do something when all operation completed  
  21. });  

这样我们就把嵌套的异步调用,改写成了顺序执行的事件处理。

更多的方式,请大家参考这篇文章,它提出了解决异步的五种模式:回调、观察者模式(事件)、消息、Promise和有限状态机(FSM)。

下一代Javscript对异步编程的增强

ECMAScript6

下一代的Javascript标准Harmony,也就是ECMAScript6正在酝酿中,它提出了许多新的语言特性,比如箭头函数、类(Class)、生成器(Generator)、Promise等等。其中Generator和Promise都可以被用于对异步调用的增强。

Nodejs的开发版V0.11已经可以支持ES6的一些新的特性,使用node --harmony命令来运行对ES6的支持。

co、Thunk、Koa

koa是由Express原班人马(主要是TJ)打造,希望提供一个更精简健壮的nodejs框架。koa依赖ES6中的Generator等新特性,所以必须运行在相应的Nodejs版本上。
 

利用Generator、coThunk,可以在Koa中有效的解决Javascript异步调用的各种问题。

co是一个异步流程简化的工具,它利用Generator把一层层嵌套的调用变成同步的写法。

  1. var co = require('co');  
  2. var fs = require('fs');  
  3.  
  4. var stat = function(path) {  
  5.   return function(cb){  
  6.     fs.stat(path,cb);  
  7.   }  
  8. };  
  9.  
  10. var readFile = function(filename) {  
  11.   return function(cb){  
  12.     fs.readFile(filename,cb);  
  13.   }  
  14. };  
  15.  
  16. co(function *() {  
  17.   var stat = yield stat('./README.md');  
  18.   var content = yield readFile('./README.md');  
  19. })();  

通过co可以把异步的fs.readFile当成同步一样调用,只需要把异步函数fs.readFile用闭包的方式封装。

利用Thunk可以进一步简化为如下的code, 这里Thunk的作用就是用闭包封装异步函数,返回一个生成函数的函数,供生成器来调用。

  1. var thunkify = require('thunkify');  
  2. var co = require('co');  
  3. var fs = require('fs');  
  4.  
  5. var stat = thunkify(fs.stat);  
  6. var readFile = thunkify(fs.readFile);  
  7.  
  8. co(function *() {  
  9.   var stat = yield stat('./README.md');  
  10.   var content = yield readFile('./README.md');  
  11. })();  

利用co可以串行或者并行的执行异步调用。

串行

  1. co(function *() {  
  2.   var a = yield request(a);  
  3.   var b = yield request(b);  
  4. })();  

并行

  1. co(function *() {  
  2.  var res = yield [request(a), request(b)];  
  3. })();  

更多详细的内容,大家可以参考这两篇文章12

总结

异步编程带来的问题在客户端Javascript中并不明显,但随着服务器端Javascript越来越广的被使用,大量的异步IO操作使得该问题变得明显。许多不同的方法都可以解决这个问题,本文讨论了一些方法,但并不深入。大家需要根据自己的情况选择一个适于自己的方法。
 

同时,随着ES6的定义,Javascript的语法变得越来越丰富,更多的功能带来了很多便利,然而原本简洁,单一目的的Javascript变得复杂,也要承担更多的任务。Javascript何去何从,让我们拭目以待。

原文链接:http://my.oschina.net/taogang/blog/267707

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多