3

I have the following code snippet. It is a promise, which is rejected after 2 seconds. And after two seconds it gives the output Error my custom error

const promise = new Promise((resolve, reject) => {
  setTimeout(() => reject('my custom error'), 2000);
});

function onSuccess() {
  console.log('Success');
}

function onError(err) {
  console.log('Error', err);
}

promise.then(onSuccess);
promise.catch(onError);
// promise.catch((err) => onError(err));

You can see I have added two promise.catch statements. And they both give the same output. My question is how is the err argument (my custom error) from the reject is being passed in the following catch statement promise.catch(onError).

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
mbaljeetsingh
  • 449
  • 5
  • 14
  • 6
    `something(x => callback(x))` and `something(callback)` are (almost) the same thing – georg Apr 20 '21 at 15:12
  • Relevant: [Confusion with how thenable callback works in Promise?](https://stackoverflow.com/q/59878462) – VLAZ Apr 20 '21 at 15:15
  • `onError` is a function which accepts one argument and executes the body of the `onError` function. `(err) => onError(err)` is a function which accepts an argument and executes the `onError` function, passing that argument… – deceze Apr 20 '21 at 15:16

3 Answers3

2

catch method takes a callback function. when the promise is rejected that callback is called with the error.

In your case then onError function is the callback. So when promise is rejected it takes that callback and calls it.

A typical example can be something like

catch(callback) {
  // some logic 
  callback(new Error('error message'));
}

So your onError function receives the argument as err object.

Do check this medium article on how a promise can typically be implemented

It will give you more idea on what is happening under the hood.

Also note that

in both cases

function onError(err) {
  console.log('Error', err);
}

promise.catch(onError);
promise.catch((err) => onError(err));

you are passing a function to catch as callback. In the first case it an a normal function will be called with whatever argument catch called its callback with. So for instance had catch method passed 3 arguments to callback all three will be available to onError

In the second case you are passing an inline arrow function. Now that acts as the callback which is called with all the arguments catch block passes but you are using only the first argument and forwarding it to onError function

Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
1

promise.catch(onError); passes a function (from the variable/constant onError) into promise.catch, so that it will get called if the promise is rejected.

promise.catch((err) => onError(err)); passes a function ((err) => onError(err)) into promise.catch, so that it will get called if the promise is rejected; that function calls onError with the argument it receives.

They do virtually the same thing. In this specific case, they do almost exactly the same thing, because the rejection callback will never be called with fewer than or more than one argument; it's only ever called with one argument. So the only difference between the first example and the second is just the extra wrapper function.

Either way, the error object that's passed to the function comes from the promise implementation, when (if) it calls the rejection handler.


I should note that sometimes, it really matters whether you have that wrapper function on there, just not with promise callbacks. For instance, there's a big difference between:

result = someArray.map(parseInt);

and

result = someArray.map(val => parseInt(val));

The difference in that case is that map calls its callback with three arguments, not just one. So the first ends up calling parseInt with three arguments, but the second calls parseInt with only one argument. Which is good, because parseInt would try to use those subsequent arguments if they were there, in ways that would almost certainly not be what the author intended. (Just as an aside: in the case of parseInt, specifically, you almost always want to hardcode the second argument: parseInt(val, 10) for decimal, for instance.)

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
1

Your question does not explicitly address it but honestly this is more complicated than it seems. Already given answers are sufficient in answering your question but you have to be careful.

It's a common practice that you may need to refer this in your .then() or .catch() blocks. Especially when your promise belongs to a certain context the two separate ways of calling onError function might cause different and unexpected results.

So say we have the whole thing in a module. The following snippet will not run and throw a js:21 Uncaught (in promise) TypeError: Cannot read property 'errMsg' of undefined at onError on your console.

class myModule{
  constructor(n){
    this.errMsg  = "my custome error";
    this.promise = new Promise((resolve, reject) => setTimeout(reject, n));
  }
  onSuccess() {
    console.log('Success');
  };
  onError() {
    console.log('Error', this.errMsg);
  };
}

var p = new myModule(2000);

p.promise.then(p.onSuccess)
         .catch(p.onError);

while this works just fine;

class myModule{
  constructor(n){
    this.errMsg  = "my custome error";
    this.promise = new Promise((resolve, reject) => setTimeout(reject, n));
  }
  onSuccess() {
    console.log('Success');
  };
  onError() {
    console.log('Error', this.errMsg);
  };
}

var p = new myModule(2000);

p.promise.then(p.onSuccess)
         .catch(e => p.onError(e));

You may use arrows to keep the this intact but still you have to be careful from where you are invoking the onError function. In the first snippet the p.onError function is passed by reference to be owned and invoked from an undefined context while in the second it's still owned and invoked by p.

In order to stick the context of the question I have used the exception (rejection) case here but most of the time these shenanigans manifest themselves in the .then() block where you may need to access some properties or methods those belong to the p module.

Redu
  • 25,060
  • 6
  • 56
  • 76