Meteor runs on top of Node.js. This means I/O activities such as reading a file or sending a request over the network won’t block the whole program. Instead, we provide callbacks that will be executed in the Event Loop later when those activities finish. Ok, I agree, that may not make a lot of sense. How about some cartoons!
Let’s say our task is to read an encrypted file, then decrypt it and get the secret content:
1 2 3 4 5 6 7 8 9 10 11 |
var aes = Meteor.require('aes-helper') , fs = Meteor.require('fs'); var getSecretData = function(key) { fs.readFile('/secret_path/encrypted_secret.txt', 'utf8', function(err, res) { if (err) console.log(err); else console.log( 'Secret: ' + aes.decrypt(res, key) ); } }; getSecretData('my-secret-key'); |
Here is what a generic, garden-variety Event Loop looks like:
The Event Loop is just a queue of functions waiting to be executed. Every time we call a function, it is put onto the Event Loop
When we execute getSecretData to decrypt and print out the secret, the function readFile get called and appear on the Event Loop:
That readFile guy doesn’t care about what happens later at all, he just tells the OS to send the file and then go away!
Some moment later, the readFile operation is completed. A guy with the name ‘callback’ will jump into the Event Loop:
Later, when the file is received, our hero appears and finishes off the job
That’s quite nice and get the job done. But what if our task is more sophisticated and require many level of async operations? We might end up with something like this:
The problem of async control flow is it makes the code more difficult to read and maintain. It would be nicer if we can have getSecretData return the secret content and print it out synchronously, like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* This code looks nicer, but sadly it doesn't work */ getSecretData = function(key) { var decryptedSecret; fs.readFile('/secret_path/encrypted_secret.txt', 'utf8', function(err, res) { if (err) console.log(err); else decryptedSecret = aes.decrypt(res, key); } return decryptedSecret; // undefined <-- oops! }; // So sweet. We have getSecretData return the value, then print it out, all synchronously. // If only life were that simple... var result = getSecretData('my-secret-key'); // undefined console.log(result); // undefined |
This code does not work, because getSecretData will not wait for the readFile operation to finish. It just goes on and return decryptedSecret as an undefined value. To solve this problem, we need a new hero. Here comes Fiber!
Meet Fiber, the big guy who can carry many functions inside him
A Fiber is a special container function. He can be put into the Event Loop like other normal functions. But Fiber has a special power: He can halt at any point in the middle of his execution, get out of the Event Loop to take a rest, then come back at any time, all at his will (or in fact, the developer’s will). When a Fiber halts, control will be passed to the next function in the Event Loop (which may be a normal function or yet another Fiber).
You properly already see the advantage here: If our Fiber contains a function that performs a time-consuming I/O activity, he can just get out of the Event Loop and wait for the result. In the mean time, we can go on and run the next functions waiting in the queue. Life is short and time is precious! When the I/O activity finishes, our Fiber can jump back in again and resume what he was doing the last time.
Here is our code, Fiber-powered:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
var Fiber = Npm.require('fibers'); // Our Fiber-powered getSecretData function getSecretData = function(key) { var fiber = Fiber.current; // get the currently-running Fiber fs.readFile('/secret_path/encrypted_secret.txt', 'utf8', function(err, res) { if (err) console.log(err); else fiber.run( aes.decrypt(res, key) ); // resume execution of this fiber. The argument passed // to fiber.run (i.e. the secret data) will become // the value returned by Fiber.yield below } // halt this Fiber for now. When the execution is resumed later, return whatever passed to fiber.run var result = Fiber.yield(); return result; }; // We wrap our code in a Fiber, then run it Fiber(function() { var result = getSecretData('my-secret-key'); console.log(result); // the decrypted secret }).run(); |
Alright, that may not make a lot of sense. Here are your cartoons:
When Fiber encounters a yield, he knows it’s time to take a rest!
Calling run() will signal the resuming of execution for this Fiber. Whatever passed to run() will become the value returned by yield()
I hear you saying: ‘Ok, that’s looks good. But the yield and run stuffs still sound weird to me’.
I got you. We’ll see something even nicer than a Fiber. It’s a Future!
You can see Future as an abstraction layer on top of Fiber. This gives us the power of Fiber with a nicer API. Like a well-groomed Fiber.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
var Future = Npm.require('fibers/future'); // Our Future-powered getSecretData function getSecretData = function(key) { var future = new Future; // create a new, bright future fs.readFile('/secret_path/encrypted_secret.txt', 'utf8', function(err, res) { if (err) console.log(err); else future.return( aes.decrypt(res, key) ); // signal that the future has finished (resolved) // the passed argument (the decrypted secret) // will become the value returned by wait() below } return future; // we return the future instance so other code can wait() for this future }; // The future method is added to the prototype object of every function // Calling future() on a function will return a Fiber-wrapped version of it (function() { // we wait for the future to finish. While we're waiting, control will be yielded // when this future finishes, wait() will return the value passed to future.return() var result = getSecretData('my-secret-key').wait(); console.log(result); }.future()) (); |
Wait! In the examples above, we have freely modified our getSecretData function. What if you come across an async function that you can’t modify (like functions from external APIs)? No worry, instead of modifying it, we can wrap it up!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// A native, garden-variety async function getSecretData = function(key, callback) { fs.readFile('/secret_path/encrypted_secret.txt', 'utf8', function(err, res) { if (err) throw new Error(err.message); else callback && callback( null, aes.decrypt(res, key) ); } }; // Let's wrap it up // What returned here is actually a future instance. When the async operation completes, // this future instance will be marked as finished and the result of the async operation // will become the value returned by wait() var getSecretDataSynchronously = Future.wrap(getSecretData); (function() { // we call wait() on the returned future instance to, well, wait for this future to finish // and get the result later when it does var result = getSecretDataSynchronously ('my-secret-key').wait(); console.log(result); }.future()) (); |
Hmm, looks like we’ll need to remember to call wait() every time. What a hassle!
Fortunately, it’s even simpler if we use Meteor.wrapAsync:
1 2 3 4 5 6 7 8 9 10 |
getSecretData = function(key, callback) { fs.readFile('/secret_path/encrypted_secret.txt', 'utf8', function(err, res) { if (err) throw new Error(err.message); else callback && callback( null, aes.decrypt(res, key) ); } }; var getSecretDataSynchronously = Meteor.wrapAsync(getSecretData); var result = getSecretDataSynchronously(key); // <-- no wait() here! return result; |
Actually there’s more to async than meets the eye. Other useful things that are worth mentioning:
– – –
Future.wrap and Meteor.wrapAsync are very selective
They only do business with native, pure async functions. That is, functions that expect a callback with error and result as arguments. Also, they only work on the server-side (since yielding is not possible on the client – there’re no Fibers living there).
– – –
Meteor.wrapAsync will turn your innocent function into Two-Face !!!
Fortunately, two-faced functions are not as destructive as Harvey Dent. In fact, they’re pretty useful: They can be called synchronously (like what we were doing above) or asynchronously (with a callback passed to them).
On server-side, methods such as HTTP.call and collection.insert/update/remove are all already pre-wrapped this way. Take HTTP.call for example: If you call it without a callback, the method will block until the response is received. If called with a callback, HTTP.call returns immediately, and will later excute the provided callback when network response has arrived.
On client-side, since blocking/yielding is not possible, we always have to provide a callback to these methods.
– – –
Fiber hiccups
By default, method calls from a client are run inside a single Fiber – they’re run one at a time. This Fiber gets access to a set of environment variables that are specific to the currently connected client (e.g. Meteor.userId()). This may result in two common problems:
1) On server-side, calling methods like HTTP.call synchronously will block other subsequent method calls from the current client. This may not be a good thing. If subsequent methods are independent from the current running method, we can save time by using this.unblock(), which will allow other method calls to be run in a new Fiber:
1 2 3 4 5 6 |
Meteor.methods({ requestSecret: function() { this.unblock(); return HTTP.call('GET', 'http://www.nsa.gov/top-secrets'); } }); |
2) “Meteor code must always run within a Fiber”
Looks familiar? This error often occurs when you try to call a third-party API with async callback. You’re not allowed to do this, since the callback function would be executed outside Fiber, without access to necessary environment variables. One way to solve this is wrapping the callback function with Meteor.bindEnvironment, which will return a Fiber-wrapped and environment-packed version of the function. The second way is using Meteor.wrapAsync like what we were doing above (actually wrapAsync already called bindEnvironment internally for us!).
I hope you’ve learned something useful about async and Meteor in this article. Happy coding!
P.S. For anyone wanting to learn more about this topic, here are two interesting classes from EventedMind:
Fantastic article. Thank you very much! (got linked in Meteor Daily) The lack of SSL hurts, though
Hi,
What do you mean by ‘the lack of SSL hurts’?
Hi,
That your site doesn’t use SSL. Sorry for late reply.
Great article, thanks for sharing! Loved the cartoons
Awesome article, loved the way you explained and the cartoons were sweet
I’m very glad to hear that the article is helpful!
Nice cartoons
Really good article! It’s a difficult topic to understand but your explanation shines. This video complements the post: https://www.eventedmind.com/feed/meteor-meteor-wrapasync
fantastic! this post just saved me hours of time!
This one line: “They can be called synchronously (like what we were doing above) or asynchronously (with a callback passed to them).”
Is what clear up the confusion for me!
Thanks again!
Pingback: Everything You Need To Know About Async & Meteor | Dinesh Ram Kali.
Pingback: Best Learning Resources for Meteor.js | 懒得折腾
Pingback: Meteor-Learning | 懒得折腾
Fantastic article.Love the way you explain with those cartoons.:)
są pierwsze wyimaginować sumę stwórz matrymonialnych, wespół z poufnymi, skoro mają że awansowanie się na nie
da im pewną przewaga. Istnieją niewyobrażalnie perfidne
natomiast skoro faktycznie toż potrafię zachwycić – bezwyjątkowe.
W 4 casusach na 5 swobodnie porwane użyciem podkreślaj do skoncentrowanego posagu.
Pingback: Meteor.js异步全解 | Meteor中国
phucnguyen.info has potential, you can make your blog go viral easily using one tricky method. Just search in google:
Sulingi’s Method To Go Viral
Clear, concise, well-thought-out article. I especially like that you included all the intermediate steps showing how Futures are actually fibers underneath.
Canada
Good Article
Pingback: List of resources to learn to build amazing apps with JavaScript – Meteor |
Pingback: Synchronous call using wrapAsync - HTML CODE
Awesome things here. I am very happy to look your post.
Thanks a lot and I’m taking a look ahead to touch you. Will you kindly drop me a mail?
Pingback: How to learn meteor | About Resarch
ifqmyidmpvjuanqfvfxfbqhrfwqbeu
home https://bluefintrading.co.uk/
Just wanted to say thank you for showing how to create a synchronous function from a custom made asynchronous function. Thank you so much, it has really helped me!!
HiI have connected my Mac to a Linux box directly using a cable (no home router involved).In Mac, I am setting a static IP address to 10.10.11.13 with subnet mask 255.255.255.0 and in Linux 10.10.11.16 with same mask. My Mac has two NICs (2nd one is connected to router and WWW). How can I add a route in Mac so all the traffic intended for the Linux box goes through first NIC? I am interested in waking the Linux machine up using something like:$ wakeonlan -i 10.10.11.16 00BA::AB:XX:XXIs this routing possible?
Robert, America only has one r in it.Slow down.That’s like a spinoff of the Russian spelling.reply from Robert: Thanks Clay. Didn’t realize I had done that. It’s fixed now.
Excelent blog Radule.Un alt amanunt, nu numai botanistul casei regale dar chiar Printul Charles este "atasat" de flora din Romania, in particular de pe langa Saschiz.De cate ori ma intorc in vizita, drumul Brasov – Sighisoara este in itinerariul nostru.Liviu,Un Brasovean in Canada
Beyond lovely! The print and your Lydia mods are just right, Nettie. I’m so very glad to hear the making and wearing of this gorgeous dress was a source of cheer up for you. What a nod to sewing as therapy!
I came to your Everything You Need To Know About Async & Meteor | Phuc Nguyen’s Blog page and noticed you could have a lot more traffic. I have found that the key to running a website is making sure the visitors you are getting are interested in your subject matter. We can send you targeted traffic and we let you try it for free. Get over 1,000 targeted visitors per day to your website. Check it out here: http://pcgroup.com.uy/15 Unsubscribe here: http://pcgroup.com.uy/2a
Nа indywidualne życzenie Klienta odpowiednie materiałydo
stworzenia wymarzonej tapicerki sprowadzam z różnych stron świata.
Ɗo renowawcji zawsze używam ekologicznych,
naturalnych skór. Proponuję kompleksowy zakres սsług
tapicerskich dla zastosowań motoryzacyjnych – oferuję tapicerowanie dla
aut osobowych, ϲiężarowych, przyczep kempingowych,
autobusóᴡ,…
Obrigado o auspicioso writeup. – na ᴠerdade foi
um lazer conta. Olha complexo ρara maiѕ adicionado agradável ԁe
você! A propósito como pоde nós estar em contato?
呵呵 我只是进来看看在媒体引导下民众会有多疯狂。大家继续做愤青 被gd牵着鼻子领上不归路吧
泽州新闻网 http://www.zezhou.net.cn/
坚决支持。也让美日韩看看我们的实力,让他们知道中国不是好欺负的。
武昌网站建设 http://www.Wcwzjs.cn
我很好奇,怎么是“俄媒”称,中国就没听声呢?
http://www.innmarry.com http://www.innmarry.com
产后忧郁症?狡辩,不要找接口,犯罪就是犯罪,灭绝人性。忧郁症是杀人的理由吗,还是亲生孩子,这样人就是恶魔!
http://www.guohuicar.com http://www.guohuicar.com
公你妹!!!一家人吃饭还用公筷,太自私了。
密云网站建设 http://www.mywzjs.cn/
完了。这就是中国人。都去日本抢购。最好永远留在日本吧。无语
http://www.ynjLjgj.com http://www.ynjLjgj.com
这是老毛时代的事情了。一个导弹下来还管个毛精气神,还是国力的问题。看到这个新闻标题我扬眉吐气啊,军演吧军演吧,去日本本土军演才好呢。
福建省医学会血液病学分会 http://www.fjhematoLogy.org
中国就像一个奴隶一下变成富翁了 所以大部分人有些不适应
长沙网站建设 http://www.cswzjs.com.cn
总之,作为一个大国,不能遇到什么事为了稳当,为了和谐,为了不折腾!人家美国是这样做的吗?人家经济不照样发展?该是我们挺起腰杆的时候了!
北京飞炫空间展览展示有限公司 http://www.feixuankj.com
老公和婆婆在我坐月子跟我吵架,哭了一个月,我有过自杀的念头,有过摔孩子的冲动,也有过抱着孩子跳楼的念头…还好,我及时控制住了自己的坏情绪,两年了,想起来只有恨。
乐亭新闻网 http://www.letingba.cn/
随着时间的迁移,这段历史会逐渐让人淡忘的!估计日本人就这么想的!
台中网 http://www.taizhong.net.cn/
坚决支持祖国接下来的一切对策!誓死拥护祖国的每一寸领土!
沌口网站建设 http://www.Dkwzjs.cn
那男人的话不可信。那女人脑袋被门挤。就算你们不要也不能那么残酷。晚上睡得着吗?
昆明飞华工贸有限公司 http://www.kmfhgm.com
要不把朝鲜的上世纪的装备也带上一起吧!!反正热闹!
江岸网站建设 http://www.jawzjs.com.cn
女人不在身边,看到这消息,觉得明天的太阳更美!!!!
平定新闻网 http://www.pingding.net.cn/
正是因为这样,所以更惨。可以能懂的人太少了。
门头沟网站建设 http://www.mtgwzjs.cn/
你都吃了几十年了 传统更是走过了几千年了 这事情 有必要强求别人么 何况是自己拉扯你大的 父母 你真要介意 以后自己用自己的筷子好了 记得自己洗
黄陂网站建设 http://www.Hpwzjs.cn
每个贪官每人留一百万,剩余全捐了人民也会感谢你们。
http://www.huguan.net.cn http://www.huguan.net.cn/
都在说降落伞…你们随随便便能想出的问题专家在造飞机前就想了无数次了,谁不想活下来?没安装降落伞必然有他的依据在里面!
http://www.lingchuan.org.cn http://www.lingchuan.org.cn/
真正打响核战争,地球就完啦,人类就要灭绝!————-这话你应该向你的美日主子说去!
石家庄绿之洲商贸有限公司 http://www.365tt315.com
瞎喷。给你降落伞只会引起混乱。你以为降落伞好玩?你去跳个试试生还记率
sf123.com http://www.sf123.es
骂医生的有本事一辈子别进医院,你们只看见少数不良医生及案例,你们看见过医生为了手术累到在手术台上吗?你们看到过医生为了医院随时招呼都不敢带老婆孩子出去旅游吗?瞎啊
满城新闻网 http://www.mancheng.net.cn/
成本高点可以,机票价格高点也行,总比出了钱还陪了命,航空公司少挣点不行呀,飞机一出事就是多少生命,应该以最高安全出发,保证安全第一。
http://www.sxtdqj.com http://www.sxtdqj.com
还行 刚开始肯定要站在前人的肩膀上 虚心学习 钻研 等后来居上 羽翼丰满 就可以单干了,中国人的学习能力还是很强的
洪山网站建设 http://www.hswzjs.com.cn
啊。。。。。。。。。。。叫八分钟都断气了?
http://www.zhengdingba.cn http://www.zhengdingba.cn/
在家里还用什么公筷,这女的也矫情,父母听了这话以为子女嫌弃自己,很伤人的好不好!你说一大堆人吃饭再准备公筷什么那还说的过去,你就和你爸吃顿饭还要公筷,太那什么了吧!有洁癖的人都不注意这个,就你矫情点!
http://www.beining.net.cn http://www.beining.net.cn/
老鬼子??要打也是针对美日发兵!以我们现在的兵力,想打亚洲哪里就能打哪里
武汉代理记账 https://www.whrdpx.com/
我觉得用公筷很有必要~特别是亲戚朋友聚餐的时候,要是谁有传染病或者什么的自己有不注意就那什么了…
http://www.qy-xws.com http://www.qy-xws.com
我看整体的一个大降落伞可行。元芳:你去办吧!
上海市徐汇区立申办公设备服务社 http://www.Lswybg.com
神舟5号都背有降落伞,飞机为什么不能背?
宁波网站建设 http://www.nbwzjs.cn
只有来过才知道真正的日本,愤青就是一群渣子
盐城市天行软件有限公司 http://www.szgjp.com
其实我感觉这航母的动力系统才是关键..虽然是改装的.但是动力方面如果是原创的那就不一样了
上海网站建设 http://www.shwzjs.net.cn
支持一下、早就该中俄在日本海、和韩国的海面、还可以跑到美国珍珠港给他演习。他们整天跑到家门口来演习了。
光谷网站建设 http://www.ggwzjs.com.cn
别动不动就说开战,你们不懂军事,不懂政治,早晚你们会知道的!
http://www.guangzhounews.org.cn http://www.guangzhounews.org.cn/
说的挺美的!先是中国开战先,并且首发胜利,到最后还是说他们自己胜利了,说的像是光明最终……战胜黑暗似的。可是没想过,单凭菲律宾的那些军人,我们中国一个两个团就可以搞定了,越南还是两个师……其他只要对付日本,美国,西南边防卫大于进攻,而且占领菲,越。
http://www.3000ok.com http://www.3000ok.es
人家医生是弱势群体,弱势群体遇到事情应该用群体的方式来解决,才能捍卫它们的尊严啊,这都不懂,还是人吗?
大兴网站建设 http://www.dxwzjs.cn/
这真的能开——玩笑!航母配套的特混舰队需要重巡洋舰、驱逐舰、护卫舰和补给舰等,舰载飞机及其起降技术,这些可不是一日之功啊。
吴桥新闻网 http://www.wuqiao.net.cn/
如果医生这行业可以废除,说风凉话的都不用看医生了,我支持。如果,废除不了,请蛋疼的闭嘴OK
青山网站建设 http://www.Qswzjs.cn
哎,悲哀,现在我们中国怎么搞的,什么人都敢骑到我们的头上欺负我们,堂堂中华拥有五千多年文明的古国,难道要毁到我们这一代吗???哎
广州网站建设 http://www.gzwzjs.net.cn
日本人素质一向很好,比中国人好万倍了,服务质量都比中国好,中国该醒醒啦
鹿泉新闻网 http://www.luquannews.cn/
坚决支持,到日本的后院去热闹一下。叫日本人看到两个与他们有领土之争的国家合到一起的力量。
沈阳市沈河区金瑞龙美术社 http://www.jrLgg.com
没听过独立用筷子吃饭死人的,但是自家人用公筷确实感觉很别扭很拘束又伤感情。好习惯也可能是坏毛病。
元氏新闻网 http://www.yuanshinews.cn/
还击得好!医护人员都这么团结一致,那些不讲道理的人就不敢肆无忌惮了!
http://www.xyxjxd.com http://www.xyxjxd.com
美日韩不是要搞什么第一岛链、第二岛链封堵中国海军进出太平洋吗,这下好了,中国海军潜艇和舰艇直接从日本海,再穿过日本本土岛国进出太平洋,哈哈
网站建设的前期准备 https://www.feimao666.com/news/790.html
中国终于让我们提起精神了,和老大哥一起演习,看日本憋气吧,支持
http://www.cdfsbz.com http://www.cdfsbz.com
非典的时候建议大家使用公筷,现在去饭店吃饭每个菜都用公筷,用公筷是件很卫生的行为,为什么这里一群人在反对,难道就是因为对象是父女的原因,这什么狗屁原因
单职业传奇 https://www.7000sf.com/
该来点铁血手段啦!不然小兔子都会欺负你拉
山阴门户网 http://www.shanyin.net.cn/
不能嫌父母脏,但是卫生也是要讲的,毕竟是父母,可以换个方式去表达,在家用公筷叶很卫生,避免交叉感染嘛
http://www.zezhou.net.cn http://www.zezhou.net.cn/
跟你男朋友你她妈就不分了吧?狗日的妮子,弄死你狗日的,应该把你射墙上
王家湾网站建设 http://www.Wjwwzjs.cn
我支持用公筷!尤其受不了出去吃饭时外人热情的夹菜给你,不好意思不吃,但实在又不想吃,吃个饭都那么纠结,现在能不出去就不出去
安徽泰源建筑工程有限责任公司 http://www.ahyxzx.com
狗日的,人不犯我我不犯人,人若犯我往死里整!
杭州网站建设 http://www.hzwzjs.net.cn
中国真要打这几个垃圾小国美国敢出手?太可笑了
http://www.xingtangnews.com.cn http://www.xingtangnews.com.cn/
太理解你了!我还是双胞胎,休产假的时候带孩子带的快发疯了……
石景山网站建设 http://www.sjswzjs.cn/
Excelente ɑqսi! Também ѕeu local carrega rápido ! Ⲟ que host da web você еstá usando?
Dá-me seu link de afiliado para ѕеu host? Quem me dera mеu web site carregado
сomo rápido ϲomo o seu lol
The orange line on the chart is the price in Bitcoin.