zoukankan      html  css  js  c++  java
  • 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的异步有所领悟。编码快乐!

    -- 蜗居苏州昆山 自由软件开发者 专注于Javascript全栈开发(Angular.js-Node.js-Meteor.js-Bootstrap) 擅长JavaEE --
  • 相关阅读:
    正则表达式大全
    函数基础(二)
    函数基础(一)
    bzoj3531 [Sdoi2014]旅行
    bzoj4785 [Zjoi2017]树状数组
    bzoj4568 [Scoi2016]幸运数字
    bzoj1975 [Sdoi2010]魔法猪学院
    bzoj1079 [SCOI2008]着色方案
    bzoj1996 [Hnoi2010]chorus 合唱队
    bzoj2326 [HNOI2011]数学作业
  • 原文地址:https://www.cnblogs.com/meteorcn/p/MeteorJS_Async_Fiber_Future_Wrap.html
Copyright © 2011-2022 走看看