Search code examples
javascriptnode.jspromisebluebird

Execute other promise only if first one didn't returned good results


So I'm struggling with this a couple days and I have found a solution for this but I feel like this isn't the good one. I currently have the following. I don't like it because I'm nesting Promises within promises. I don't know if this is fine but it doesn't look like it.

What I'm trying to accomplish with this code is first to check the cache database for a value if it is not there then I'll check the real database.

Any tips/tricks/pointers/comments on how to do this more elegantly?

var getData = function() {
    var cancel = false
    var cache = db.getFromCache(query)
      .then((data) => {
      // Check if data is up to date
         if (uptodate) { 
            return Promise.resolve(data) 
         }
         cancel = true      
       })

   return cache
        .then(() => {
          if (cancel)
             return db.getFromDatabase().then( //code)
    }
}

ps: this code may or may not run I just made it quickly for this question. I can't past the real code here


Solution

  • When you're in a .then() handler, you can do anyone of the following:

    1. Return a value - that value becomes the resolved value of the parent promise. So, there is no need to return Promise.resolve(value). You can just return value.

    2. Return a promise - When you return a promise, it is chained to the parent promise and the parent promise will not resolve until this new promise resolves and the resolved value of this returned promise will become the resolved value of the parent promise.

    3. Throw an Exception - If a .then() handler throws, that exception is automatically caught by the promise infrastructure and is turned into a rejection so throw err works similarly to return Promise.reject(err).

    As such, when you're in your .then() handler, you can just check to see if the cache data is valid and, if so, just return it. Otherwise, return a new promise to get the data.

    var getData = function() {
        return db.getFromCache(query).then((data) => {
             // Check if data is up to date
             if (uptodate) { 
                // return cached data, will be resolved value of promise
                return data; 
             } else {
                // get data from db, return promise that will be chained
                return db.getFromDatabase();
             }
       })
    }
    
    getData().then(...)
    

    Your code is way more complicated than need be:

    1. You don't need Promise.resolve(). You can just return the value.
    2. You don't need the cancel variable at all. You can do all your work inside the first .then() handler.
    3. You don't need the second .then() handler.