How to break promise chain on error

2020-04-17 05:33发布

问题:

Consider this snippet

fetch(`http://${api.host}:${api.port}/user`)
  .then(function(data) {
    return data.json();
  }, function(err) {
    throw new Error(`Couldn\'t fetch user data from server: ${err.message}`);
  }).then(function(eparkUser) {
    for (var key in eparkUser) {
      if (eparkUser.hasOwnProperty(key) && !user.hasOwnProperty(key)) {
        user[key] = eparkUser[key];
      }
    }
    done(null, user);
  }, function(err) {
    throw new Error(`Couldn't parse returned json: ${err.message}`);
  }).catch(function(e) {
    done(e);
  });

Isn't throw supposed to break the chain and trigger .catch ? How to achieve this behaviour? Becauce now both throw are getting executed and I see message:

Error: Couldn't parse returned json: Couldn't fetch user data from server: request to http://localhost:3010/user failed and that not what I want.

P.S. fetch is npm node-fetch module

回答1:

No, throw does not jump to catch. It does reject the promise, and all error handlers installed on it will be invoked. In your case, that's the error handler installed by the then call. Notice that .catch(handler) is just sugar for .then(null, handler).

Your current code works like

try {
    try {
        try {
            var data = fetch(`http://${api.host}:${api.port}/user`)
        } catch(err) {
            throw new Error(`Couldn\'t fetch user data from server: ${err.message}`);
        }
        var eparkUser = data.json();
    } catch(err) {
        throw new Error(`Couldn't parse returned json: ${err.message}`);
    }
    for (var key in eparkUser) {
        if (eparkUser.hasOwnProperty(key) && !user.hasOwnProperty(key)) {
            user[key] = eparkUser[key];
        }
    }
    done(null, user);
} catch(e) {
    done(e);
}

To solve your problem, you'll need to nest your handlers, and install the JSON-parse-handler only on that particular promise:

fetch(`http://${api.host}:${api.port}/user`)
    .then(function (data) {
        return data.json()
            .then(function (eparkUser) {
                for (var key in eparkUser) {
                    if (eparkUser.hasOwnProperty(key) && !user.hasOwnProperty(key)) {
                        user[key] = eparkUser[key];
                    }
                }
                return user;
            }, function(err) {
                throw new Error(`Couldn't parse returned json: ${err.message}`);
            });
    }, function(err) {
        throw new Error(`Couldn\'t fetch user data from server: ${err.message}`);
    })
    .then(done.bind(null, null), done);