場(chǎng)景
遠(yuǎn)古時(shí)代
我們?cè)诰帉慹xpress后臺(tái),經(jīng)常要有許多異步IO的處理。在遠(yuǎn)古時(shí)代,我們都是用chunk函數(shù)處理,也就是我們最熟悉的那種默認(rèn)第一個(gè)參數(shù)是error的函數(shù)。我們來(lái)模擬一個(gè)Mongo數(shù)據(jù)庫(kù)的操作,感受一下。
mongoDb.open(function(err, db){ if(!err){ db.collection("users", function(err, collection){ if(!err){ let person = {name: "yika", age: 20}; collection.insert(person, function(err, result){ if(!err){ console.log(result); } }); } }) }});這個(gè)也就是被我們所詬病的callback hell,一堆橫向金字塔,如果將回調(diào)拆分成函數(shù),則會(huì)變得非常支離破碎。為了防止到惡心到大家,我甚至沒(méi)有寫關(guān)于錯(cuò)誤的處理,正常來(lái)說(shuō),每一個(gè)異步的操作都需要都它的error進(jìn)行相應(yīng)的顯示或處理的。
Promise時(shí)代
后來(lái)進(jìn)入了好一點(diǎn)的時(shí)代就是Promise,我們也可以稱作鏈?zhǔn)讲僮鳌jP(guān)于Promise,我也是之前有專門寫過(guò)一系列的博文,有興趣可以回頭翻一下。這里來(lái)看看,將以上改寫之后的狀況。
let person = {name: "yika"};mongoDb .open() .then(function(database){ return database.collection("users"); }) .then(function(collection){ return collection.insert(person); }) .then(function(result){ console.log(result); }) .catch(function(e){ throw new Error(e); })我們可以看到,我們將金字塔已經(jīng)平鋪成一條線狀結(jié)構(gòu)了。相比之前惡心難以維護(hù)的chunk函數(shù),變成了promise函數(shù),并且錯(cuò)誤的處理也變得十分優(yōu)雅。但是我們?nèi)匀徊豢珊鲆暷承﹩?wèn)題,例如我們必須忍受各個(gè)邏輯被一個(gè)又一個(gè)的then()包裹起來(lái),每一個(gè)函數(shù)都有其獨(dú)立的作用域,如果為了共享某個(gè)數(shù)據(jù)就必須掛在最外層,最重要的還是,它與我們熟悉的同步編程仍然有差別。
Generator時(shí)代
TJ大神,借著ES6的Generator迭代器,最早實(shí)現(xiàn)了異步編程同步化的功能,也就是最為我們所熟知的co庫(kù)。我們通過(guò)co(function *(){})可以使函數(shù)內(nèi)部通過(guò)迭代器來(lái)控制。而co在這里則是充當(dāng)了啟動(dòng)器的角色。關(guān)于Generator和co我在之前的博文也同樣說(shuō)過(guò)。
let co = require("co");co(function *(){ let db, collection, result; let person = {name: "yika"}; try{ db = yield mongoDb.open(); collection = yield db.collection("users"); result = yield collection.insert(person); }catch(e){ console.error(e.message); } console.log(result);});我們已經(jīng)非常接近同步編程了,在co包裹的函數(shù)內(nèi)部,只有一個(gè)異步執(zhí)行完畢,才會(huì)繼續(xù)執(zhí)行下面的代碼。并且錯(cuò)誤的處理也是通過(guò)try and catch進(jìn)行實(shí)現(xiàn)的。不過(guò)我們不得不承認(rèn)的是,迭代器終究不是為異步而存在的。里面的
新聞熱點(diǎn)
疑難解答
圖片精選