0

I have JSON-RPC provider like this (transpiled with babel and webpack):

export default function() {
    var id = 1;
    function request(method, params) {
        return JSON.stringify({
            id: id++,
            method: method,
            params: params || []
        });
    }
    var uri;
    this.setup = function(user_uri) {
        uri = user_uri;
    };
    this.$get = ['$http', '$q', function($http, $q) {
        function rpc(method, params) {
            return $http({
                method: 'POST',
                url: uri,
                data: request(method, params)
            }).then(response => response.data);
        }
        var defer = $q.defer();
        rpc('system.describe').then(data => {
            var service = {};
            data.result.procs.forEach(spec => {
                service[spec.name] = function(...args) {
                    var defer = $q.defer();
                    if (args.length == spec.params.length) {
                        return rpc(spec.name, args).then(data => {
                            if (data.error) {
                                defer.reject(data.error);
                            } else {
                                defer.resolve(data.result);
                            }
                        });
                    } else {
                        defer.reject('Invalid arity expected ' +
                                     spec.params.length +
                                     ' got ' +
                                     args.length);
                    }
                    return defer.promise;
                };
            });
            defer.resolve(service);
        });
        return defer.promise;
    }];
};

and I call one function:

        service.login('user', 'password').then(function(token) {
            if (token) {
                localStorage.setItem('notes_token', token);
                localStorage.setItem('notes_username', 'user');
            }
            console.log('token: ' + token);
        }).catch(function(error) {
            console.log(error);
        });

the request is returning error and I got this in console:

token: undefined [err] Possibly unhandled rejection: user not active

Why I don't get console.log from catch and have then executed?

I've also tried:

        service.login('user', 'password').then(function(token) {
            if (token) {
                localStorage.setItem('notes_token', token);
                localStorage.setItem('notes_username', 'user');
            }
            console.log('token: ' + token);
        }, function(error) {
            console.log(error);
        });

and get the same results. I'm using angular 1.6.3.

jcubic
  • 61,973
  • 54
  • 229
  • 402
  • 1
    Avoid the [deferred antipattern](http://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! – Bergi Mar 28 '17 at 17:04

1 Answers1

0

Avoid the deferred antipattern! Try to never use $q.defer(). When your rpc() function rejects its result promise, you're just ignoring that - an unhandled rejection.

You will want to use

this.$get = ['$http', '$q', function($http, $q) {
    function rpc(method, params) {
        return $http({
            method: 'POST',
            url: uri,
            data: request(method, params)
        }).then(response => response.data);
    }
    return rpc('system.describe').then(data => {
//  ^^^^^^
        var service = {};
        for (const spec of data.result.procs) {
            service[spec.name] = function(...args) {
                if (args.length == spec.params.length) {
                    return rpc(spec.name, args).then(data => {
                        if (data.error) {
                            throw data.error;
//                          ^^^^^
                        } else {
                            return data.result;
//                          ^^^^^^
                        }
                    });
                } else {
                    return $q.reject('Invalid arity expected ' +
//                  ^^^^^^^^^^^^^^^^
                                 spec.params.length +
                                 ' got ' +
                                 args.length);
                }
            };
        }
        return service;
//      ^^^^^^
    });
}];
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • "Try to never use $q.defer()" -- sorry I dont understand this. $q.defer is widely used. – Petr Averyanov Mar 28 '17 at 18:09
  • It should only be used at the lowest level. If you are calling an asynchronous function, you don't need `$q.defer` - the function should return a promise. Only for functions that you cannot modify, you'll need to write a wrapper that uses a deferred. And yes, many usages of `$q.defer` are misguided. – Bergi Mar 28 '17 at 20:50