3
votes

I am not able to catch the Exception/Error that is happening inside of the Resolve promise. Can someone explain if there is a way to catch this error:

createAsync = function() {
    var resolve, reject,
    promise = new Promise(function(res, rej) {
        resolve = res;
        reject = rej;
    });
    promise.resolve = resolve;
    promise.reject = reject;
    return promise;
};

promise = createAsync()
promise.then(function myresolver(){
    throw Error('wow')
})


// Catching the error here
try {
  promise.resolve()
} catch(err) {
  console.log( 'GOTCHA!!', err );
}

EDIT:

Let me explain me better, I'm trying to create an API and the user only have access to the promise resolve/reject part:

// This is my API user does not have access to this part
promise = createAsync()
promise
.then(function(fun) {
    if (typeof fun != 'function')
        throw Error('You must resolve a function as argument')
}).catch(function(err){
    // Some internal api tasks...
    return Promise.reject(err)
})

Now the solution I would like to give him, but does not work:

// Here is where the user can resolve the promise.
// But must be able to catch the error
promise.catch(function(err){
    console.log("GOTCHA", err)
})
promise.resolve('This must be a function but is a string');

Any ideas?


More info: Yes is an antipattern for the common usage. This is a remote procedure call API, so the user must be able to reject or resolve. And the calls are async so the best approach is to use promises. I wouldn't say is an antipattern for this case. Actually is the only pattern. (I can't use Async/Await)

3
// Catching the error here no you aren't - you promise.resolve() doesn't reject the promise ... your promise.then ... throw will "reject" THAT promise (the one returned by .then) not the one in promiseJaromanda X
"Exporting" the resolve and reject functions provided to the executor (the function passed to the promise constructor), in your case by polluting the promise object with additional properties, is an anti-pattern. The entire point of the design of the promise constructor is that resolving and rejecting is isolated within the executor. Your approach allows any random person who happens to acquire one of your promise objects to resolve or reject it, which is almost certainly not good program design.user663031
@EnZo torazaburo is right, you should always separate resolving capabilities from the promise. And usually you don't want a user to call resolve or reject - the better promise pattern is to simply accept a promise from the user that he can resolve/reject at his own disposal.Bergi
On which side of the RPC is the "user" sitting? It might help if you could show the actual code (some API object?) instead of the createAsync pseudocode.Bergi
Oh, you were right, the real code is complicated. Unfortunately I couldn't figure out what the f in that localProcedureCall was and how it uses/needs to use the req object. However, I can tell you that localProcedureCall should not take resolve and reject callbacks but rather return a promise (and you likely want to use .then(…, …) instead of .then(…).catch(…)), and that the pattern for dop.protocol.subscribe basically should look like return new Promise(resolve => storeRequest(node, request_info, resolve); })Bergi

3 Answers

3
votes

Let me explain me better, I'm trying to create an API and the user only have access to the promise resolve/reject part. Now the solution I would like to give him does not work. Any ideas?

Don't put everything onto that initial promise object. It sounds what you really need to expose to your user is a) a way to resolve (which includes rejection) and b) a way to get the result (promise) back. So all you need to do is give him a function:

function createAsync() {
    var resolve;
    var promise = new Promise(function(r) { resolve = r; })
    .then(function(fun) {
        if (typeof fun != 'function')
            throw Error('You must resolve a function as argument')
    }).catch(function(err){
       // Some internal api tasks...
       throw err;
    });
    return function(value) {
        resolve(value);
        return promise;
    };
}

and he'd use it like

var start = createAsync();
// possibly later
start('This must be a function but is a string').catch(function(err){
    console.log("GOTCHA", err)
});
// or
start(Promise.reject(new Error('doomed to fail'))).catch(…);

but actually this pattern is still convoluted and much too complicated. Simply give your createAsync function a parameter (that might receive a promise if the user needs to delay passing the fun) and be done with it:

function createAsync(valu) {
    return Promise.resolve(val).then(function(fun) {
        if (typeof fun != 'function')
            throw Error('You must resolve a function as argument')
    }).catch(function(err){
       // Some internal api tasks...
       throw err;
    });
}

createAsync('This must be a function but is a string').catch(function(err) {
    console.log("GOTCHA", err)
});
// or
createAsync(new Promise(function(resolve) {
    // later
    resolve('This must be a function but is a string');
})).catch(function(err) {
    console.log("GOTCHA", err)
});
2
votes

Warning: as pointed out by @torazaburo "Exporting" the resolve and reject functions provided to the executor (the function passed to the promise constructor), in your case by polluting the promise object with additional properties, is an anti-pattern. The entire point of the design of the promise constructor is that resolving and rejecting is isolated within the executor. Your approach allows any random person who happens to acquire one of your promise objects to resolve or reject it, which is almost certainly not good program design.

With that warning in mind, your call to promise.resolve() doesn't reject the promise ... your promise.then ... throw will "reject" THAT promise (the one returned by .then) not the one in promise

rewrite your code as follows:

promise = createAsync()
promise // the call to promise.resolve will resolve THIS promise, so .then will execute
.then(function myresolver(){
    throw Error('wow')
}) // .then returns a NEW promise, in this case rejected with Error('wow')
.catch(function(e) {
    console.log("GOTCHA", e)
});

promise.resolve()

and you'll see the expected GOTCHA in the console

1
votes

Jaromanda's answer already explained that you must use a rejection handler or catch to handle asynchronous errors using promises.

Also make sure to read torazaburo's comment explaining why your approach is an anti-pattern.

If you really must use this approach and also require try/catch for some reason, ES7 gives you a way via async functions

(async function f() {
  const createAsync = function() {
    var resolve, reject,
      promise = new Promise(function(res, rej) {
        resolve = res;
        reject = rej;
      });
    promise.resolve = resolve;
    promise.reject = reject;
    return promise;
  };

  const promise = createAsync();
  promise.resolve();

  // Catching the error here
  try {
    await promise.then(function() {
      throw Error('wow')
    });
  } catch (err) {
    console.log('GOTCHA!!', err);
  }
})()