Search code examples
javascriptnode.jsexceptiontry-catches6-promise

nodejs promise better way to handle errors happening in promise implementation?


This is probably asked many times but I couldn't find a proper example for my solution. Here is the main example where I am returning a promise and I mocked the response body to make it fail. I am trying to handle the exception to catch it and log it properly.

const request = require('request');

var url = "https://bittrex.com/Api/v2.0/pub/market/GetTicks?marketName=BTC-STRAT&tickInterval=hour";

function requestMarketData() {
    return new Promise(function(resolve, reject) {
        request(url, function(err, res, body) {
            if (err) {
                console.log(err);
                return reject(err);
            }
            console.log("GET: " + url);
            var result = JSON.parse("<HTML>"); // make JSON.parse fail
            return resolve(result);
        });
    });
}

async function getMarketData() {
    var result = await requestMarketData();
}

getMarketData();

First way I am trying to handle it;

async function getMarketData() {
    try {
        var result = await requestMarketData();
    } catch(err) {
        console.log("Failed result: " + err);
    }
}

which didn't work which is expected because of asynchronous work.

Second way by appending catch handler for the returned promise;

function requestMarketData() {
    return new Promise(function(resolve, reject) {
        request(url, function(err, res, body) {
            if (err) {
                console.log(err);
                return reject(err);
            }
            console.log("GET: " + url);
            var result = JSON.parse("<HTML>"); // make JSON.parse fail
            return resolve(result);
        });
    }).catch(err => {
        console.log("Failed result: " + err);
    });
}

didn't work as well.

Third way;

function requestMarketData() {
    return new Promise(function(resolve, reject) {
        request(url, function(err, res, body) {
            if (err) {
                console.log(err);
                return reject(err);
            }
            console.log("GET: " + url);
            var result = [];
            try {
                result = JSON.parse("<HTML>"); // make JSON.parse fail
            } catch(err) {
                result = [{foo: "bar"}];
                return reject(result);
            }
            return resolve(result);
        });
    });
}

Which finally worked. However, my question is there a better way to handle these kind of errors outside from promise implementation?

Thanks a lot!


Solution

  • Your requestMarketData function needs to cause the promise to be rejected when JSON parsing fails. Right now, it throws an error at JSON.parse, and there’s nothing to catch it (the Promise constructor only catches errors thrown synchronously inside it). You can catch it yourself:

    function requestMarketData() {
        return new Promise(function(resolve, reject) {
            request(url, function(err, res, body) {
                if (err) {
                    console.log(err);
                    return reject(err);
                }
                console.log("GET: " + url);
    
                var result;
    
                try {
                    result = JSON.parse("<HTML>"); // make JSON.parse fail
                } catch (err) {
                    return reject(err);
                }
    
                return resolve(result);
            });
        });
    }

    but Promise#then will also catch it for you:

    function requestMarketData() {
        return new Promise(function(resolve, reject) {
            request(url, function(err, res, body) {
                if (err) {
                    console.log(err);
                    return reject(err);
                }
    
                console.log("GET: " + url);
                return resolve(body);
            });
        }).then(JSON.parse);
    }

    Equivalently, with an async function:

    function requestMarketData() {
        let body = await new Promise(function(resolve, reject) {
            request(url, function(err, res, body) {
                if (err) {
                    console.log(err);
                    return reject(err);
                }
    
                console.log("GET: " + url);
                return resolve(body);
            });
        });
    
        return JSON.parse(body);
    }