1. 回調金字塔及理想中的解決方案
我們都知道javascript是一門單線程異步非阻塞語言。異步非阻塞當然是它的一個優點,但大量的異步操作必然涉及大量的回調函數,特別是當異步嵌套的時候,就會出現回調金字塔的問題,使得代碼的可讀性非常差。比如下面一個例子:
var fs = require('fs');fs.readFile('./file1', function(err, data) {console.log(data.toString());fs.readFile('./file2', function(err, data) {console.log(data.toString());})})這個例子是先后讀取兩個文件內容并打印,其中file2的讀取必須在file1讀取結束之后再進行,因此其操作必須要在file1讀取的回調函數中執行。這是一個典型的回調嵌套,并且只有兩層而已,在實際編程中,我們可能會遇到更多層的嵌套,這樣的代碼寫法無疑是不夠優雅的。
在我們想象中,比較優雅的一種寫法應該是看似同步實則異步的寫法,類似下面這樣:
var data;data = readFile('./file1');//下面的代碼是第一個readFile執行完畢之后的回調部分console.log(data.toString());//下面的代碼是第二個readFile的回調data = readFile('./file2');console.log(data.toString());這樣的寫法,就完全避免回調地獄。事實上,koa就讓我們可以使用這樣的寫法來寫異步回調函數:
var koa = require('koa');var app = koa();var request=require('some module');app.use(function*() {var data = yield request('http://www.baidu.com');//以下是異步回調部分this.body = data.toString();})app.listen(3000);那么,究竟是什么讓koa有這么神奇的魔力呢?
2. generator配合promise實現異步回調同步寫法
關鍵的一點,其實前一篇也提到了,就是generator具有類似"打斷點"這樣的效果。當遇到yield的時候,就會暫停,將控制權交給yield后面的函數,當下次返回的時候,再繼續執行。
而在上面的那個koa例子中,yield后面的可不是任何對象都可以哦!必須是特定類型。在co函數中,可以支持promise, thunk函數等。
今天的文章中,我們就以promise為例來進行分析,看看如何使用generator和promise配合,實現異步同步化。
依舊以第一個讀取文件例子來分析。首先,我們需要將讀文件的函數進行改造,將其封裝成為一個promise對象:
var fs = require('fs');var readFile = function(fileName) {return new Promise(function(resolve, reject) {fs.readFile(fileName, function(err, data) {if (err) {reject(err);} else {resolve(data);}})})}//下面是readFile使用的示例var tmp = readFile('./file1');tmp.then(function(data) {console.log(data.toString());})關于promise的使用,如果不熟悉的可以去看看es6中的語法。(近期我也會寫一篇文章來教大家如何用es5的語法來自己實現一個具備基本功能的promise對象,敬請期待呦^_^)
|
新聞熱點
疑難解答
圖片精選