Meteor.js异步全解

 翻译来源: http://phucnguyen.info/blog/everything-you-need-to-know-about-async-meteor/

 

Meteor是运行在Node.js之上的。这意味着I/O行为,比如读文件或者发送网络请求不会阻塞整个程序。事实上,当异步行为执行结束后,我们可以提供回调。好了解不?下面会有图画解释。

假设我们想读一个加密过的文件,接着解密出内容:

 

而更通用,多样的事件序列长成这样:

meteor_async_a

事件序列只是等待执行的函数队列而已。每当调用函数时,就放到事件序列里边去。

当我们执行函数getSecretData去解密并打印文档内容时,函数readFile就会被调用,出现在事件序列里边。

meteor_async_b

读文件函数readFile并不关心他后面执行什么,这哥们只是告诉系统发送文件,接着就滚蛋了!

 

分分秒,readFile结束。‘callback’回调这货就会跳进事件序列:

meteor_async_c

很快,收到文件后,英雄归来,完成后面的所有工作。

 

很好很有用吧?! 可是如果任务更复杂,需要多层异步该怎么办?结果就成这吊样:

callback-hell

so-many-callbacks

 

真蛋疼!异步流程控制代码太变态了,无法阅读和维护!要是getSecretData能同步返回内容就好了,像这样:

 

可惜,这样的代码不可行,因为getSecretData会在readFile结束前就执行了,直接返回undefined。解决这问题,非英雄莫属,那就是Fiber-王者归来!

meteor_async_f

接触Fiber,他是个可以容纳多个函数的无敌英雄! 

Fiber其实就是特别的容器函数。他可以跟普通函数一样被扔进事件序列。但他也别有魔力:可以在任意执行点暂停,跳出执行序列,任意时间后再回来,任由程序员调戏!Fiber暂停时,流程控制权就接力到事件序列里边的下一个函数(普通函数,新Fiber函数都可以)。

你可能已经看到好处了:如果Fiber含有费时的I/O行为,它可以跳出事件序列,等待结果。同时,我们也可以运行序列里的下一个函数。人生苦短,时间珍贵!I/O结束,Fiber可以再转回来,从上次执行点接着来.下面是用Fiber写的代码:

 

可能还不好理解是吧?下面的图标更直观:

meteor_async_d

Fiber发现yield时,他会休息一下!

meteor_async_e

调用run()就回复Fiber的执行,任何传递到run()将会变成yield()的返回值。

你还叫?“看起来还行。但是yield run这货,我感觉有点奇葩”。

我同意!还有比Fiber更猛的大神。那就是Future!

你可以把Future当作Fiber的抽象。这货提供了更强大的API,像是驯养的Fiber。

 

嘿咻!上面的列子都是可以自由修改getSecretData函数的。可是当异步函数不好修改是怎么办?比如第三方API。小事一桩,不需要修改,包一下就行了! 

嗯,好像每次调用下wait就可以了。还是有点烦!

哈哈,用Meteor.warapAsync,他还可以更简便! 

I never know

 

实际上,除了吸引眼球,我们还有一些异步相关的话题可以聊聊:

– – –

Future.wrap 和 Meteor.wrapAsync不是万能药

他们只适合原生的纯异步函数。就是有回调,返回error,result那种函数。还有,他们只能在服务器端有用,因为yielding在客户端不行-没用Fibers。

– – –

Meteor.wrapAsync会把你纯真的函数变成双半脸!!!

 

two-face

幸运的是,双面函数也不太坏。有时候他们很有用,他们可以同步调用(上面几种方案),也可以异步调用(传一个回调函数)。

服务器端,HTTP.call, collection.insert/update/remove都已经内置了这种包裹方式。比如HTTP,如果直接调用,方法会等到response返回;如果提供回调函数,他就直接跳出,等网络返回response再条用回调函数。

客户端,由于不能用阻塞,只能提供回调函数。

– – –

Fiber 瑕疵

默认,客户端调用是在Fiber里的-----一次一个。这个Fiber可以访问当前用户的环境变量(比如Meteor.userId())。这也会产生问题:

1)服务器端,同步调用HTTP.call这类方法会阻塞当前用户的后续方法。这未必是什么好事情。如果后续方法跟当前方法无关的话,其实可以使用this.unblock(),这样其他方法调用就会在新的Fiber里进行

 

2) “Meteor代码必须在Fiber里边执行”

似曾相识不?错误总是不断当你调用第三方异步API时发生。不能这样搞,因为回掉函数在Fiber之外执行了,无法访问环境变量。一种解决方案就是用Meteor.bindEnvironment包一下,他能返回Fiber包过新版函数。方案2就是用Meteor.wrapAsync(实际wrapAsyncn内部就是调用的bindEnvironment ).


 

希望你对Meteor的异步有所领悟。编码快乐!

 

posted on 2015-07-02 22:33  码流星  阅读(3140)  评论(0编辑  收藏  举报

导航