COMBO--组合拳打穿回调地狱~
我想應(yīng)該會(huì)有很多像我一樣的前端聽(tīng)說(shuō)js可以開(kāi)發(fā)后臺(tái)時(shí),激動(dòng)地踏上了node.js之路,這條路上第一個(gè)挑戰(zhàn),就是回調(diào)地獄。
app.get("/changePassword?**",function(req,res){if(req.cookies.username){pool.getConnection(function(err,connection){if (err) {console.log(err+"--from pool connection");res.send("修改密碼失敗,數(shù)據(jù)庫(kù)連接錯(cuò)誤");} else{connection.query("USE userInfo",function(err,rows){if (err) {console.log(err+"--from using database");res.send("修改密碼失敗,數(shù)據(jù)庫(kù)使用錯(cuò)誤");} else{var selectQuery = "SELECT * FROM users WHERE userName="+"'"+req.cookies.username+"'";connection.query(selectQuery,function(err,rows){if (err) {console.log(err+"--from selectQuery");res.send("修改密碼失敗,數(shù)據(jù)庫(kù)查詢錯(cuò)誤");} else{if (req.query.password==rows[0].password) {var updateQuery = "UPDATE users SET password="+"'"+req.query.newPassword+"' WHERE username="+"'"+req.cookies.username+"'";connection.query(updateQuery,function(err,rows){if (err) {console.log(err+"--from updateQuery");res.send("修改密碼失敗,數(shù)據(jù)庫(kù)更新錯(cuò)誤");} else{res.send("修改密碼成功");}});/*connection.query update end*/} else{res.send("修改密碼失敗,原始密碼錯(cuò)誤");}}});/*connection.query select end*/}});/*connection.query using database end*/}if(connection){connection.release()};});/*pool.getConnection end*/} else {res.send("修改密碼失敗,登錄失效");}});/*app.get end*/這種造型的代碼就是“邪惡金字塔”,或者說(shuō)“回調(diào)地獄”,callback hell
我遇到的第一個(gè)障礙就是它,它讓代碼難以維護(hù),難以修改,橫向發(fā)展,非常不美觀
于是我開(kāi)始試圖解決這個(gè)問(wèn)題,為此,我求助了很多大神,看了很多帖子,被告知《ES6入門》這本書(shū)可以解決我的問(wèn)題,于是從promise then到*yield到async/await
看到async/await我以為就皆大歡喜,問(wèn)題解決了,然而nodejs目前需要babel轉(zhuǎn)碼才能使用async/await,很麻煩,而且對(duì)我這個(gè)新手很不友好。
在segmentfault上提問(wèn)許久,發(fā)現(xiàn)有個(gè)asyncawait模塊,可以模仿async/await模型來(lái)操作promise對(duì)象
將如下代碼添加到你的js文件中
var async = require("asyncawait/async"); var await = require("asyncawait/await");var foo = async (function() {var resultA = await (firstAsyncCall());var resultB = await (secondAsyncCallUsing(resultA));var resultC = await (thirdAsyncCallUsing(resultB));return doSomethingWith(resultC); });await()里面可以放promise對(duì)象,也可以放異步回調(diào)函數(shù),只要它有類似的返回機(jī)制,這樣一來(lái),就能提前使用async/await模式寫(xiě)代碼了,一開(kāi)始的回調(diào)地獄會(huì)變得如下代碼一樣,清晰易懂
//登錄路由 app.get("/loginForm?**", async(function(req, res) {try {var connection = await(poolp.getConnection());var selectQuery = "SELECT password FROM users WHERE username ='" + req.query.username + "'";var rows = await(connection.query(selectQuery));if (rows.length == 0) throw "登錄失敗,用戶不存在";if (rows[0].password != req.query.password) {throw "登錄失敗,密碼不正確";} else {res.send("登錄成功");}} catch (err) {res.send(err);}//記得釋放connection,不然很快就會(huì)達(dá)到上限if(connection) pool.releaseConnection(connection); }));不幸的是,await()里面放回調(diào)函數(shù)會(huì)使得代碼很臃腫,如果放promise對(duì)象,就保持了與async/await模式的一致性。
nodejs的mysql模塊,提供了pool,connection來(lái)操作數(shù)據(jù)庫(kù),可是它們都不是promise對(duì)象,我嘗試自己封裝成promise對(duì)象
很蛋疼,而且DBobj無(wú)法正確返回對(duì)象,不過(guò)國(guó)外有大神早就解決了這個(gè)問(wèn)題
npm install promise-mysql var mysqlp = require('promise-mysql'); poolp = mysqlp.createPool({host: 'localhost',user: 'root',password: 'root',database: 'userInfo',connectionLimit: 10 });就這么將mysql提供的對(duì)象轉(zhuǎn)化為了promise對(duì)象,于是上面的登錄路由就可以運(yùn)行了,簡(jiǎn)潔明了,要加正則或者別的什么驗(yàn)證隨時(shí)都能加,只需要在兩行代碼之間插入邏輯,再也不用框起一大片代碼然后調(diào)縮進(jìn)了!
相應(yīng)的,fs模塊,mail模塊也應(yīng)該有promise版本,大家可以去npm上面搜索
最后,我希望我的文章能幫助像我一樣的小白打敗回調(diào)地獄,一起踏上nodejs的探索之旅
總結(jié)
以上是生活随笔為你收集整理的COMBO--组合拳打穿回调地狱~的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 迷你世界皮肤能送人吗
- 下一篇: 知乎账号信任设备在哪