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的異步有所領悟。編碼快樂!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM