Hammerbot
Hammerbot

Reputation: 16364

Promise chaining with functions

I am trying to use promises for a small new project. But I have some problems with understanding how I could organize my code better, with functions. Problem is, I want my functions to handle things, and my main code to handle other things. So let's see this code:

function doSomething (isGoingToResolve = true) {
    return new Promise((resolve, reject) => {
    if (isGoingToResolve) {
        resolve("something")
    } else {
        reject("something else")
    }
  }).then(response => {
    console.log("in my function",response)
  }).catch(error => {
    console.log("in my function",error)
  })
}

doSomething().then(response => {
    console.log("in my main call", response)
})

With this code, the console will log in my function something and in my main call undefined: https://jsfiddle.net/hkacvw2g/

So I found two solutions to solve my problem, but I just don't like them:

The first one is to create a variable, use a .then() on the variable, and then return the variable (https://jsfiddle.net/hkacvw2g/1/):

function doSomething (isGoingToResolve = true) {
    let promise = new Promise((resolve, reject) => {
    if (isGoingToResolve) {
        resolve("something")
    } else {
        reject("something else")
    }
  })

  promise.then(response => {
    console.log("in my function",response)
  }).catch(error => {
    console.log("in my function",error)
  })

  return promise
}

And the second solution (https://jsfiddle.net/hkacvw2g/2/):

function doSomething (isGoingToResolve = true) {
    return new Promise((resolve, reject) => {
    if (isGoingToResolve) {
        resolve("something")
    } else {
        reject("something else")
    }
  }).then(response => {
    console.log("in my function",response)
    return new Promise(resolve => {
        resolve(response)
    })
  }).catch(error => {
    console.log("in my function",error)
    return new Promise((resolve,reject) => {
        reject(error)
    })
  })
}

Am I missing a better solution to solve my problem?

Upvotes: 2

Views: 964

Answers (2)

user663031
user663031

Reputation:

You can write a tap function, to tap into a promise chain, and do something while passing along the result, and a parallel tapCatch function, to tap into errors while rethrowing them:

const tap      = fn => value  => { fn(value);  return value; };
const tapCatch = fn => reason => { fn(reason); throw reason; };

Now you can write your code as:

function doSomething(isGoingToResolve = true) {
  (isGoingToResolve ? 
    Promise.resolve("something") : 
    Promise.reject("something else")
  )
  .then( tap     (response => console.log("in my function", response)))
  .catch(tapCatch(error    => console.log("in my function", error)));
}

doSomething()
  .then(response => console.log("in my main call", response));

However, actually your first solution is better. It reduces the risk of messing up the promise chain by inadvertently forgetting to, or not realizing that you have to, return the original value in then clauses, or rethrow in catch clauses which such clauses are meant only for logging purposes or other side-effects.

You could also pollute the Promise prototype with something like tap (we'll call it thenDo), making it a bit easier to use:

Promise.prototype.thenDo = function(ifFulfilled, ifRejected) {
  return this.then(
    value => { ifFulfilled(value); return value; },
    reason => { ifRejected(reason); throw reason; });
};
Promise.prototype.catchDo = function(ifRejected) {
  return this.catch(reason => { ifRejected(reason); throw reason; });
};

Now you can write

function doSomething(isGoingToResolve = true) {
  (isGoingToResolve ? 
    Promise.resolve("something") : 
    Promise.reject("something else")
  )
  .thenDo (response => console.log("in my function", response))
  .catchDo(error    => console.log("in my function", error));
}

Upvotes: 1

Martin Adámek
Martin Adámek

Reputation: 18429

You can simply return the value (or re-throw the error) and it will be resolved in promise chain:

function doSomething (isGoingToResolve = true) {
  return new Promise((resolve, reject) => {
    if (isGoingToResolve) {
      resolve("something")
    } else {
      reject("something else")
    }
  }).then(response => {
    console.log("in my function",response)
    return response;
  }).catch(error => {
    console.log("in my function",error)
    throw error;
  })
}

You might not want that throw error, it depends on how you want to handle your rejections. This way when you re-throw the error, you should catch it when calling the doSomething() method.

Upvotes: 2

Related Questions