Promises Tutorial by Irakli Nadareishvili
  • Introduction
  • Turning Callbacks Into Promises
  • Chain Parallel with Sequential
  • Conditions and Promises
  • Keeping Promise Chains Flat
  • Async and Await
  • Async/Await & Express, Mocha etc.
  • One More Thing (Go)...
  • One More Thing (Python)...
  • One More Thin (Nim)…
Powered by GitBook
On this page

Was this helpful?

Conditions and Promises

Sometimes your asynchronous function calls another asynchronous function conditionally. Writing such code in an elegant way may take a bit of effort. Case in point: let's consider application logic, in which we cache response from an API call and therefore only make an API call if the information is stale or missing. An if statement where part of it is calling asynchronous logic and part is not can get messy. Let's see an example code where we try to untangle the complexity.

Note: this is an example code for demonstration purposes-only, it is missing trivial parts for brevity and is therefore not runnable as-is:

const Promise     = require('bluebird');
const rp          = require('request-promise');
const fakepromise = require('fakepromise');

class SomeModel {

  constructor() {
    this.cachedEntity = {};
  }

  lookupValue() {
    let waitForRefresh;
    if (!this.isFresh()) {
      console.log("Rereshing entity...")
      waitForRefresh = this.refreshEntity();
    } else {
      console.log("Entity from cache...")
      // Fake wait, creates a fulfilled promise:
      waitForRefresh = Promise.resolve(this.cachedEntity);
    }

    return new Promise((resolve, reject) => {
      waitForRefresh.then((response) => {
        response = this.processResponse(response);
        this.cachedEntity = response; // refresh cache
        resolve(response);
      }).catch((err) => {
        reject(err);
      });
    })
  }

  isFresh() {
    if (!this.cachedEntity.lastFresh) {
      return false;
    }

    // or if older than 5 secs - consider not-fresh
    if ((Date.now() - this.cachedEntity.lastFresh) > 5000) {
      return false;
    }

    return true;
  }

  processResponse(response) {
    response.processed = true;
    return response;
  }

  refreshEntity() {
    const retValue = {};
    retValue.lastFresh = Date.now();
    retValue.value = Math.random() * 700; // 0 - 700
    return fakepromise.promise(200, retValue);
  }
}

let model = new SomeModel();
model.lookupValue().then(response1 => {
  console.log(response1);
  return model.lookupValue();
}).then(response2 => {
  console.log(response2)
});

In summary, by introducing a variable that is assigned to the sub-call invoking a promise and turning non-async part of the if logic into a fake promise, we can make code look uniform and clean. Which is what you see in the implementation of lookupValue() function. The refreshEntity() function implementation is not directly related to the trick we are explaining, but is included here to bring more clarity to the context of the discussion.

PreviousChain Parallel with SequentialNextKeeping Promise Chains Flat

Last updated 5 years ago

Was this helpful?

Side note: source files of all examples and instructions for how to execute, are located at:

https://github.com/inadarei/promises123-code