简体   繁体   中英

Async call based on a response from a previous call, avoiding callback hell

So I usually deal with async functions by using the .then chain. But this time it doesn't solve it. This is the situation.

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);
    })
]);

So this worked, and all was great. But now I decided to change the way to select the active event . I'm calling a collection called generalInfo and grabbing the ID to the current event from there. Here's what I have so far:

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);
})

But this code starts to look like a callback hell.

I also tried something like this:

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));

It's not completed but it kind of shows my way of thinking. But again, no luck.

So how can I get along with async without chaining .then forever? I need to pass all the returned objects to the render function.

You can just nest earlier, which has the advantage of overlapping more as well (see *** comment(s)):

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);
});

If you do that generalInfo => event thing a lot, you might wrap it in a utility function.

Alternately, if they shouldn't overlap like that, you can minimize the nesting by adding another 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);
})

This should work.

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);
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM