基于先前调用的响应的异步调用,避免回调地狱
Posted
技术标签:
【中文标题】基于先前调用的响应的异步调用,避免回调地狱【英文标题】:Async call based on a response from a previous call, avoiding callback hell 【发布时间】:2018-12-20 16:14:08 【问题描述】:所以我通常使用.then
链来处理异步函数。但这一次并没有解决它。情况就是这样。
return Promise.all([
Banner.findOne(),
event.findOne(
status: true
),
Account.find(
accType: 'employer'
)
.then(([banner, event, account]) =>
res.render('index',
title: 'Web Project Studio',
user: req.user,
banner: banner,
event: event,
employer: account
);
).catch(e =>
console.error(e);
)
]);
所以这很有效,一切都很好。但现在我决定改变选择活跃event
的方式。我正在调用一个名为 generalInfo
的集合,并从那里获取当前事件的 ID。到目前为止,这是我所拥有的:
return Promise.all([
Banner.findOne(),
GeneralInfo.findOne(),
Account.find(
accType: 'employer'
)
]).then(([banner, generalInfo, account]) =>
Event.findById(generalInfo.activeEventId).then(r =>
console.log('test');
var event = r;
res.render('index',
title: 'Web Project Studio',
user: req.user,
banner: banner,
event: event,
employer: account
);
).catch(e => console.log(e));
).catch(e =>
console.error(e);
)
但是这段代码开始看起来像一个回调地狱。
我也试过这样的:
var banner = await Banner.findOne().catch(e => console.log(e));
var currentEvent = await GeneralInfo.findOne().catch(e => console.log(e));
currentEvent.then(async r =>
var event = await Event.findOneById(r.activeEventId).catch(e => console.log(e));
).catch(e => console.log(e));
它还没有完成,但它有点显示我的思维方式。但同样,没有运气。
那么我怎样才能在不永远链接 .then
的情况下与 async 相处呢?我需要将所有返回的对象传递给render
函数。
【问题讨论】:
在我发布答案之前,我很好奇你是否愿意从你的承诺(或承诺)中创建一个可观察的。如果是这样,您可以与 map、concat 和所有那些让您以类似程序(但当然是异步)的方式执行此类操作的出色的可观察运算符合并。如果你对 rxjs 不感兴趣,尽管我会保留它。 我不知道那是什么,但我完全愿意提供任何答案 啊:你真的(真的!)需要查找“rxjs”并探索“observables”。基本上,它们允许您将数据表示为可以与其他流合并的“流”,等待其他流准备好,等等。 Promise 有利于它们的优点(几乎是即时的一次性执行),但是当您需要管理多个异步流时,特别是如果它们需要按顺序管理、加入、重试和很快。这需要一些努力,但现在,如果你在做异步工作,你真的需要 rxjs。 无论如何,一个 Observable(表示异步数据流的东西)可以包装一个 Promise,以便您可以使用 Observable 运算符等。一定要查找“rxjs 中的多个流”,您将获得各种教程和代码示例,了解如何去做。 会的。谢谢! 【参考方案1】:您可以更早地嵌套,这也具有重叠更多的优点(请参阅***
评论):
return Promise.all([
Banner.findOne(),
GeneralInfo.findOne()
.then(generalInfo => Event.findById(generalInfo.activeEventId)), // ***
Account.find(
accType: 'employer'
)
).then(([banner, event, account]) =>
res.render('index',
title: 'Web Project Studio',
user: req.user,
banner: banner,
event: event,
employer: account
);
).catch(e =>
console.error(e);
);
如果你经常做 generalInfo => 事件的事情,你可以把它包装在一个实用函数中。
或者,如果它们不应该那样重叠,您可以通过添加另一个 then
来最小化嵌套:
return Promise.all([
Banner.findOne(),
GeneralInfo.findOne(),
Account.find(
accType: 'employer'
)
]).then(([banner, generalInfo, account]) =>
return Event.findById(generalInfo.activeEventId).then(event => // ***
return [banner, event, account]; // ***
); // ***
).then(([banner, event, account]) =>
res.render('index',
title: 'Web Project Studio',
user: req.user,
banner: banner,
event: event,
employer: account
);
).catch(e =>
console.error(e);
)
【讨论】:
【参考方案2】:这应该可行。
return Promise.all([
Banner.findOne(),
GeneralInfo.findOne(),
Account.find(
accType: 'employer'
)
]).then(async ([banner, generalInfo, account]) =>
res.render('index',
title: 'Web Project Studio',
user: req.user,
banner: banner,
event: await Event.findById(generalInfo.activeEventId),
employer: account
);
).catch(e =>
console.error(e);
)
【讨论】:
以上是关于基于先前调用的响应的异步调用,避免回调地狱的主要内容,如果未能解决你的问题,请参考以下文章