Home > Software engineering >  Wrapping Promises to do something when consuming, resolved and rejected: differences with chaining?
Wrapping Promises to do something when consuming, resolved and rejected: differences with chaining?

Time:12-08

I'd like to make a function what "wrap" Promise and:

  1. Do something when the promise is invoked (1)
  2. Do something when the promise is resolved, but retain original value (2)
  3. Do something when the promise is rejected but retain the error (3)

I'm not very confident with promises... here is what I may do:

const wrap = (promiseToWrap) => {
  return new Promise((resolve, reject) => {
    console.log('loading...'); // (1)
    
    promiseToWrap
      .then(res => {
        console.log('show success toast'); // (2)
        resolve(res);
      })
        .catch(err => {
        console.log('show error toast') // (3)
        reject(err);
      });
  });
}

Assuming this solution is right, what's the difference with chaining a new Promise (the one that do "something") with the passed promiseToWrap?

CodePudding user response:

You don't need to create a new promise, you can chain the existing one. To keep the return value and error, just return the value and re-throw it respectively:

const wrap = promiseToWrap => {
  console.log('loading...'); // (1)
    
  return promiseToWrap.then(
    res => {
      console.log('show success toast'); // (2)
      return res;
    },
    err => {
      console.log('show error toast') // (3)
      throw err;
    }
  );
}

Better though, write it with async:

const wrap = async (promiseToWrap) => {
  console.log('loading...'); // (1)
  
  try {
    const res = await promiseToWrap;
    console.log('show success toast'); // (2)
    return res;
  } catch (err) {
    console.log('show error toast') // (3)
    throw err;
  }
}

Alternatively, you can simply "latch onto" the promise to trigger additional callbacks, and return the original promise unchanged:

const wrap = promiseToWrap => {
  console.log('loading...'); // (1)
    
  promiseToWrap.then(
    res => console.log('show success toast'), // (2)
    err => console.log('show error toast') // (3)
  );

  return promiseToWrap;
}

CodePudding user response:

What you wrote is equivalent to

const wrap = (promiseToWrap) => {
  console.log('loading...'); // (1)
  return promiseToWrap
      .then(res => {
        console.log('show success toast'); // (2)
        return res;
      })
        .catch(err => {
        console.log('show error toast') // (3)
        throw err;
      });
}

or more succinctly

const wrap = async (promiseToWrap) => {
  console.log('loading...'); // (1)
  try {
    const result = await promiseToWrap;
    console.log('show success toast'); // (2)
    return result;
  } catch (err) {
    console.log('show error toast') // (3)
    throw err;
  }
};

This probably isn't what you want.

Note that Promise callbacks are immediately invoked, by the time the Promise to wrap is passed to your function it is already "loading" and may well be resolved.

  • Related