1

Pretty sure I could do this with async/await just fine, but I'd like to understand how to implement this logic without.

Workflow:

  • Find a job in the database
  • if the job exists, find a Person, if not, send a response to the frontend
  • then do Person logic

Code:

    Job.findByPk(jobId)
       .then(job => {
           if(job) return Person.findOne(...)
           else res.status(404).json(...)
       })
       .then(person => {
           if(person)
               // Do person logic here
       })
       .catch(err => ...);

The problem is that this logic obviously doesn't work. The person parameter in the second .then() block could be undefined if either no job or no person is found.

So a solution would be to do this in the first .then() block:

       .then(job => {
           if(job) // store the job locally
           else res.status(404).json(...)

           return Person.findOne(...)
       })

but that means that the database is searched regardless of if a Job is found or not rather than being conditional on a job being found

How do structure this in a way that makes more sense?

Thanks

NickW
  • 1,207
  • 1
  • 12
  • 52
  • Nick, you should not put an answer into your question here on stackoverflow. Questions here are only for questions. If you want to show your own answer, you can actually show it in an answer. – jfriend00 May 11 '21 at 03:22
  • Sorry, will change it now! – NickW May 11 '21 at 03:53

3 Answers3

1

This is a lot simpler with await (assuming you make the parent function async):

try {
    const job = await Job.findByPk(jobId);
    if (!job) {
         return res.status(404).json(...)
    }
    const person = await Person.findOne(...);
    if (person) {
        ...
    } else {
        ...
    }
} catch(e) {
    console.log(e);
    res.sendStatus(500);
}

What makes this flow so much simpler is that all variables are in the same scope and you can return anywhere you want to finish the flow.

If you're going to stick with the previous .then() logic, then see this answer: How to chain and share prior results with promises for multiple different options.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Actually, having read that link I did decide to go with breaking out of the promise chain. So I tested for `if(!job) throw new Error(...)` (I actually add statusCodes etc as well), and have error handling deal with the response. So not sure if this question should be re-marked as duplicate. Thanks for your help either way! – NickW May 11 '21 at 03:00
1

You can simply add .thens within the first .then.

Job.findByPk(jobId)
  .then(job => {
    if(job)
      return Person.findOne(...)
        .then(person => {
          if(person)
          // Do person logic here
        });
    else res.status(404).json(...)
  })
  .catch(err => ...);
Naman Goel
  • 1,525
  • 11
  • 16
  • Yeah true, was trying not nest anything though. For no other reason than I knew it was possible and wanted to learn how. The answer was breaking out of the promise chain. Thanks for the answer though! – NickW May 11 '21 at 03:19
  • 1
    @NickW not nesting is a very good rule. An easy way to avoid nesting, is to put the nested logic into it's own function. – Evert May 11 '21 at 03:21
0

The selected answer is the best way of acheiving what I wanted - ie just using async/await - but for anyone who wants to know how I stuck with chaining, it's just breaking out of it properly. I ended up doing this by throwing an error (which is then handled elsewhere)

       .then(job => {
           if(!job) {
              const error = new Error('Job not found');
              error.statusCode(404);
              throw error;
           } else  {
              return Person.findOne(...)
           }

       })
       .then(person => { // Person logic })
       .catch(err => next(err))
NickW
  • 1,207
  • 1
  • 12
  • 52