Sir Sudo
Sir Sudo

Reputation: 31

How do I conditionally run a .then() function in a .then .catch chain?

My code resembles this:

router.post("/", (req, res, next) => {
foo()
.then((result) => {
    res.send(result)
})
.catch((error) => {
    cosnole.log(error)
})
//I only want the bar() function and everything below it to run if the first promise is rejected and the first .catch function ran
bar()
.then((data) => {
    res.send(data)
})
.catch((error) => {
    console.log(error)
})

})

I'd like to only run the bar() function and the .then .catch functions after it only if the first promise is rejected and the .catch function fires off.

I've tried this:

router.post("/", (req, res, next) => {
rejected = false
foo()
.then((result) => {
    res.send(result)
})
.catch((error) => {
    rejected = true
    console.log(error)
})
if(rejected == true)
    bar()
    .then((data) => {
        res.send(data)
    })
    .catch((error) => {
        console.log(error)
    })

})

but the bar() function never gets executed when the first foo() function's error is caught and the promise is rejected.

Upvotes: 2

Views: 551

Answers (5)

Try returning bar to chain your promise.

router.post("/", (req, res, next) => {
    foo()
    .then((result) => {
        res.send(result)
    })
    .catch((error) => {
        console.log(error);
        return bar;
    })
    .then((data) => {
        res.send(data);
    })
    .catch((error) => {
        console.log(error)
    });
});

----------------- EDIT -----------------

Here's a fully testable copy of an ExpressJS sample with your problem:

const express = require("express");
const app = express();
const port = process.env.PORT || 4000;

app.get("/", function(req, res) {
    foo = new Promise(function(resolve, reject) {
        // resolve("resolved"); // Uncomment for resolve
        reject("rejected");
    });

    bar = new Promise(function(resolve, reject) {
        resolve("myData");
    });

    foo.then((result) => {
        res.send(result);
    }).catch((error) => {
        console.log(error);
        return bar;
    }).then((data) => {
        res.send(data);
    });
});

app.listen(port, function () {
    console.log("Listening on port: " + port);
});

Upvotes: -1

Bergi
Bergi

Reputation: 664920

As others mentioned, you just need to move the code inside that catch handler.

However, you will probably want to simplify and correct your code to

router.post("/", (req, res, next) => {
    foo().catch(bar).then(result => {
        res.send(result);
    , error => {
        console.error(error);
        res.sendStatus(500); // or next(error) or whatever
    });
})

If you want to log errors from foo even when they're handled by bar, you might need

foo().catch(error => {
    console.log(error, "(handled by bar)");
    return bar();
}).…

Upvotes: 3

Jaime Blázquez
Jaime Blázquez

Reputation: 328

Given the asynchronous nature of your code, if (rejected==true) will always be false, because that code is executed before the first then or catch.

You can:

Move all the bar()[...] code inside the .catch()

foo()
.then((result) => {
    res.send(result)
})
.catch((error) => {
    console.log(error)
    bar()
    .then((data) => {
        res.send(data)
    })
    .catch((error) => {
        console.log(error)
    })
})

move all the conditional execution inside a .then() after the .catch()

rejected = false
foo()
.then((result) => {
    res.send(result)
})
.catch((error) => {
    console.log(error)
    rejected = true
})
.then(() => {
  if(rejected) {
    bar()
    .then((data) => {
        res.send(data)
    })
    .catch((error) => {
        console.log(error)
    })
  }
})

Upvotes: 0

Igor
Igor

Reputation: 62238

Move the call to inside the catch.

router.post("/", (req, res, next) => {
    foo()
    .then((result) => {
        res.send(result)
    })
    .catch((error) => {
        cosnole.log(error);
        return bar()
        .then((data) => {
            res.send(data)
        })
        .catch((error) => {
            console.log(error)
        });
    });
});

Upvotes: 4

guijob
guijob

Reputation: 4488

I/O calls happens asynchronously, so your if code gets running before res.send() return any response. There are several ways to handle this scenario, here is another way using asyn/await in order to write code which looks like synchronous:

router.post("/", async (req, res, next) => {
rejected = false
try {
  await foo()
    .then((result) => {
      res.send(result)
    })
} catch {
  rejected = true
  console.log(error)
}
if(rejected == true)
  bar()
  .then((data) => {
    res.send(data)
  })
  .catch((error) => {
    console.log(error)
  })
})

Upvotes: 0

Related Questions