[英]Is this an acceptable method of avoiding callback hell in old versions of node?
[英]Avoiding callback hell in node
我有這個功能
/* GET main page */
router.get('/', (req, res, next) => {
Account.find({accType: 'Employer'}, (err, col) => {
if (err) {
console.log(err);
} else {
Banner.findOne((err, banner) => {
if (err) {
console.log(err);
} else {
// Determine whether there is at least one awaiting account.
Account.findOne({accType: 'Awaiting'}, (err, doc) => {
if (err) {
console.log(err);
} else {
if (doc != null) {
var awaiting = true;
}
console.log(doc);
res.render('admin/', {
title: 'Admin pannel',
user: req.user,
employers: col,
areAwaiting: awaiting,
banner: banner,
)
}
}
);
}
});
}
});
});
我嘗試使用如下異步模塊:
async.parallel(calls, (err, col) => {
if (err)
console.log(err);
else {
console.log(col);
res.render('admin/', {
title: 'Admin pannel',
user: req.user,
employers: col[0],
banner: col[1],
areAwaiting: col[2],
})
}
});
現在。 我得到的錯誤是wrapAsync(...)不是一個函數 。 我試圖將我的函數放在這樣的匿名函數中:
() => {
Account.find({accType: 'Employer'}, (err, col) => {
if (err)
console.log(err);
else return col;
})
}
但是隨后代碼凍結了。 我也試過這個:
(col) => {
Banner.findOne((err, doc) => {
if (err)
console.log(err);
else return doc;
});
return col
},
但是效果一樣 知道我在做什么錯嗎? 回調地獄版本可以使用,但是很丑陋且不可維護。
戴夫·米漢(Dave Meehan)回答。 必須對其進行略微編輯以使其起作用。
router.get('/', (req, res) => {
return Promise.all([
Account.find(),
Banner.findOne(),
Account.findOne({accType: 'Awaiting'}),
]).then(([employers, banner, awaiting]) => { // Right here
if (awaiting != null)
var areAwaiting = true;
res.render('admin/', {
title: 'Admin pannel',
user: req.user,
employers: employers,
areAwaiting: areAwaiting,
banner: banner,
});
}).catch(e => {
console.error(e)
});
});
我不得不關閉陣列中then
進入()
通過不將其寫為回調地獄總是可以避免的。 不過,在這種情況下,讓我們先重寫一些代碼。
首先,如果收到錯誤,您可以提早紓困,因此無需在所有調用中使用else語句。 這將為您消除很多范圍。
因此,只需重寫部分代碼,您就可以將其變成如下所示的形式:
router.get('/', (req, res, next) => {
getData((err, data) => {
if (err) return console.error(err)
res.render('admin/', { /* .. */ })
})
})
function getData (cb) {
Account.find({accType: 'Employer'}, (err, col) => {
if (err) return cb(err)
Banner.findOne((err, banner) => {
if (err) return cb(err)
Account.findOne({accType: 'Awaiting'}, (err, doc) => {
if (err) return cb(err)
cb(null, { col, banner, doc })
})
})
})
}
現在,讓我們回到async
的用法上,在這里使用它是一個好主意,因為實際上不知道要依次調用Account.find()
, Banner.findOne()
和Account.findOne()
。
您的問題是您使用的async.parallel
錯誤,它假定函數數組(或對象)具有回調。
看起來可能如下所示:
async.parallel({
col: cb => Account.find({accType: 'Employer'}, cb),
banner: cb => Banner.findOne(cb),
doc: cb => Account.findOne({accType: 'Awaiting'}, cb)
}, (err, result) => {
// access result.col, result.banner and result.doc
})
現在我們可以重構上面的getData
,因此最終結果可能類似於:
router.get('/', (req, res, next) => {
getData((err, data) => {
if (err) return console.error(err)
res.render('admin/', { /* data.doc, data.banner, data.doc */ })
})
})
function getData (cb) {
async.parallel({
col: cb => Account.find({accType: 'Employer'}, cb),
banner: cb => Banner.findOne(cb),
doc: cb => Account.findOne({accType: 'Awaiting'}, cb)
}, cb)
}
這看起來很干凈,實際上不需要使用Promises。
這大概就變得簡單了,並假設:
您正在使用Express或類似的路由處理程序,並且可以返回承諾而不是使用回調
您正在使用Mongoose或類似的DB,並且可以返回一個Promise而不是使用回調。
檢查您的版本以獲得Promise支持。
您似乎至少缺少一些Banner的查詢參數,並且需要弄清楚其中的任何一個是否相關,或者如圖所示,它們可以並行運行。
router.get('/', (req, res) => {
return Promise.all([
Account.find(),
Banner.findOne(),
Account.findOne({ accType: 'Awaiting' }),
]).then(([ col, banner, doc ]) => {
res.render('admin/', {
title: 'Admin pannel',
user: req.user,
employers: col,
areAwaiting: awaiting,
banner: banner,
);
}).catch(e => { console.error(e) });
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.