我有以下代码,你可以看到,函数内部的每个函数都依赖于封闭函数的返回值。但问题是当我继续使用这种方法进行编码时,会发生回调地狱。如何避免这种地狱?
User.getUserDetail(req.user.id, function(userDetail) {
if(req.user.entity_id != '-1') {
Entity.getEntityPrimary(req.user.entity_id, function(entityPrimary) {
Entity.getEntityPayment(req.user.entity_id, function(entityPayment) {
if(entityPayment.length > 0) {
Entity.subscriptionInfo(entityPayment[0]['date'], entityPayment[0]['exp_date'], function(isSubscribed) {
res.render('capitol', {
user: req.user,
title: 'MCIC',
user_detail: userDetail,
entity_primary: entityPrimary,
entity_payment: entityPayment,
subscriber: true,
is_subscribed: isSubscribed
})
})
} else {
res.render('capitol', {
user: req.user,
title: 'MCIC',
user_detail: userDetail,
entity_primary: entityPrimary,
entity_payment: entityPayment,
subscriber: false
})
}
})
})
} else {
res.render('capitol', {
user: req.user,
title: 'MCIC',
user_detail: userDetail
})
}
})
模型文件如下
const MySql = require('../comms/mysql')
const User = module.exports = {}
User.getUserByUsername = function(username, callback) {
MySql.connection.query('SELECT id, username, password, is_active, email, mobile, user_type_id, entity_id FROM `user` WHERE `username` = ?', username, function(err, rows, fields) {
callback(rows)
})
}
User.getUserById = function(id, callback) {
MySql.connection.query('SELECT id, username, password, is_active, email, mobile, user_type_id, entity_id FROM `user` WHERE `id` = ?', id, function(err, rows, fields) {
callback(err, rows)
})
}
User.getUserDetail = function(id, callback) {
MySql.connection.query('SELECT first_name, last_name, dob, address_no, address_street, address_district, address_postal_code, profile_picture, user_id FROM `user_detail` WHERE `user_id` = ?', id, function(err, rows, fields) {
callback(rows)
})
}
我在生产网站上使用此代码。如何轻松地从回调地狱过渡到结构良好的代码?
答案 0 :(得分:0)
使用JavaScript承诺
step1(function (value1) {
step2(value1, function(value2) {
step3(value2, function(value3) {
step4(value3, function(value4) {
// Do something with value4
});
});
});
});
可以制作
Q.fcall(promisedStep1)
.then(promisedStep2)
.then(promisedStep3)
.then(promisedStep4)
.then(function (value4) {
// Do something with value4
})
.catch(function (error) {
// Handle any error from all above steps
})
在此处阅读更多Link to Q.js
答案 1 :(得分:0)
要获得快速奖励,您可以将回调函数解压缩为模块级别的命名函数:
// Before: Deeply nested
asyncOperationA(function(resA) {
asyncOperationB(resA, function(resB) {
asyncOperationC(resB, function(resC) {
console.log(resC)
})
})
})
// After: flattened
function handleA(resA) {
asyncOperationB(handleB)
}
function handleB(resB) {
asyncOperationC(handleC)
}
function handleC(resC) {
console.log(resC)
}
asyncOperationA(handleA)
更好的选择是修改您的代码以使用promises。使用async / await关键字可获得最大的可读性。要使用async / await,您需要拥有相当新的Node版本或使用转换器将其转换为vanilla JavaScript。
答案 2 :(得分:0)
使用async await:
async function() {
const userDetail = await User.getUserDetail(req.user.id);
if (req.user.entity_id != '-1') {
// you can batch the two into simulatenous queries (see below)
const entityPrimary = await Entity.getEntityPrimary(req.user.entity_id);
const entityPayment = await Entity.getEntityPayment(req.user.entity_id);
if (entityPayment.length > 0) {
const isSubscribed = await Entity.subscriptionInfo(entityPayment[0]['date'], entityPayment[0]['exp_date']);
res.render('capitol', {
user: req.user,
title: 'MCIC',
user_detail: userDetail,
entity_primary: entityPrimary,
entity_payment: entityPayment,
subscriber: true,
is_subscribed: isSubscribed
});
} else {
res.render('capitol', {
user: req.user,
title: 'MCIC',
user_detail: userDetail,
entity_primary: entityPrimary,
entity_payment: entityPayment,
subscriber: false
});
}
} else {
res.render('capitol', {
user: req.user,
title: 'MCIC',
user_detail: userDetail
});
}
}
我使用这种模式。我使用了Babel,但还有其他选项可以获得异步等待支持。我碰巧使用PostgreSQL和pg-promise,我的同步查询看起来像这样:
const results = await db.tx(t => t.batch([query1, query2]));
答案 3 :(得分:0)
你可以使用像这样的async / await
来删除回调地狱
const Promise = require('bluebird');
const User = Promise.promisifyAll(require('PATH_TO_USER'));
const Entity = Promise.promisifyAll(require('PATH_TO_ENTITY'));
async function yourController(req, res, next) {
try {
const userDetail = await User.getUserDetail(req.user.id);
if(req.user.entity_id !== -1) {
const entityPrimary = await Entity.getEntityPrimary(req.user.entity_id);
const entityPayment = await Entity.getEntityPayment(req.user.entity_id);
if(entityPayment.length > 0) {
const isSubscribed = await Entity.subscriptionInfo(entityPayment[0]['date'], entityPayment[0]['exp_date']);
return res.render('capitol', {
user: req.user,
title: 'MCIC',
user_detail: userDetail,
entity_primary: entityPrimary,
entity_payment: entityPayment,
subscriber: true,
is_subscribed: isSubscribed
})
} else {
return res.render('capitol', {
user: req.user,
title: 'MCIC',
user_detail: userDetail,
entity_primary: entityPrimary,
entity_payment: entityPayment,
subscriber: false
})
}
} else {
return res.render('capitol', {
user: req.user,
title: 'MCIC',
user_detail: userDetail
})
}
} catch(e) {
// handle exception here
}
}
步骤
async
关键字添加到您的控制器,例如async function yourController(req, res, next)
bluebird
await