DEV Community

Discussion on: Callbacks vs Promises in JavaScript

Collapse
 
aminnairi profile image
Amin

Hi Will.

You can catch errors when chaining promise in a single catch.

fetch("https://jsonplaceholder.typicode.com/posts/1").then(function(response) {
    return response.json();
}).then(function(post) {
    return fetch(`https://jsonplaceholder.typicode.com/users/${post.userId}`);
}).then(function(response) {
    return response.json();
}).then(function(user) {
    console.log("User who has posted the first post");
    console.log(user);
}).catch(function(error) {
    console.error("An error occurred");
    console.error(error);
});

As you can see, I'm only using one catch, and it will catch any error thrown in any branch of the chain. Try removing a character from one of the URLs to trigger an error and see the output.

You could even use async/await keywords to modelize your problem in a more procedural form.

"use strict";

const fetch = require("node-fetch");

async function main() {

    try {

        const url = "https://jsonplaceholder.typicode.com";
        const postResponse = await fetch(`${url}/posts/1`)
        const post = await postResponse.json();
        const userResponse = await fetch(`${url}/users/${post.userId}`);
        const user = await userResponse.json();

        console.log("User who has posted the first post");
        console.log(user);

    } catch (error) {

        console.error("An error occurred");
        console.error(error);

    }

}

main();
Collapse
 
wichopy profile image
Will C.

Thanks for the reply. I knew about the single catch, but I was wondering for a more complex example what people would do. Say instead of hitting the same API server for each call, you are hitting different ones, each with their own error responses.

I guess you could have a single catch, and have a unique handler for each error type, but I found this was not as clean as I liked.

My solution to handle a scenario like this was storing an any errors caught mid promise chain in a variable and handling that error in a more procedural manner. I updated your example with how I would do it. Using async/await makes this way of handling errors cleaner than doing everything in the catch block imo.

const fetch = require("node-fetch");

async function main() {
  try {
        const url = "https://jsonplaceholder.typicode.com";
        let err
        const postResponse = await fetch(`${url}/posts/1`).catch(error => err = error)

        if (err) { /* Handle the posts error and return */}

        const post = await postResponse.json()

        const userResponse = await fetch(`${url}/users/${post.userId}`).catch(error => err = error);

        if (err) { /* Handle the users error and return */}

        const user = await userResponse.json();

        console.log("User who has posted the first post");
        console.log(user);

    } catch (error) {

        console.error("Handle all other errors");
        console.error(error);

    }

}

main();
Thread Thread
 
aminnairi profile image
Amin • Edited

I understand what you are trying to do. You could use custom Error subclasses which allow you to keep handling errors in the catch part while still having some control over which kind of error is thrown instead of a generic one.

"use strict";

class PostResponseError extends Error {
    constructor(...parameters) {
        super(...parameters);

        this.name = "PostResponseError";
    }
}

class UserResponseError extends Error {
    constructor(...parameters) {
        super(...parameters);

        this.name = "UserResponseError";
    }
}

async function main() {
    try {
        const url = "https://jsonplaceholder.typicode.com";
        const postResponse = await fetch(`${ url }/posts/1`);

        if (!postResponse.ok) {
            throw new PostResponseError("Error with the response");
        }

        const post = await postResponse.json();
        const userResponse = await fetch(`${ url }/users/${ post.userId }`);

        if (!userResponse.ok) {
            throw new UserResponseError("Error with the response");
        }

        const user = await userResponse.json();

        console.log("User who has posted the first post");
        console.log(user);
    } catch (error) {
        if (error instanceof PostResponseError) {
            console.log("Error with the post response");
        } else if (error instanceof UserResponseError) {
            console.log("Error with the user response");
        } else {
            console.error("Unexpected error");
        }

        console.error(error);
    }
}

main();
Thread Thread
 
wichopy profile image
Will C.

Beautiful 😍