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