Lifting Functions into Promises in JavaScript

Article summary

When working on a JavaScript project, I usually spend a lot of time around promises. Lately, I’ve been using this helpful function called liftP that makes working with promises a little bit easier.

liftP is a higher-order function that takes a function as a parameter and returns a new function that is “lifted” into a promise. For example, if I have a function that takes a number and returns a string, passing that function through liftP will produce a new function that takes a promise of a number and returns a promise of a string.

Using liftP allows me to design functions without worrying about the structure of a promise around my data types.

Here’s how liftP is implemented:


const liftP = (fn) => {
  return (...args) => {
    return Promise.all(args).then((x) => fn.apply(null, x));
  };
};

Usage


const toString = (x) => `${x}`;
const a = 1;
const b = toString(a); // b === '1'

const toPromiseOfString = liftP(toString); 
const d = Promise.resolve(2);
const e = toPromiseOfString(d); // e is a promise of a string 
const f = await e; // f === '2' 

I’ve found this function most useful when dealing with chains of promises. For example, say I have a function that returns a promise and some other utility functions that process the results of that promise. Instead of writing the utility functions to be aware of the promise structure, I can write the simpler, non-promise implementation.

When I need to chain the utility functions with the function that returns a promise, I can lift the functions when chaining them. In this example, I’m using Ramda’s pipe function to chain a few functions together:


const getUsers = () => {
  return Promise.resolve([
    { firstName: 'Joe', lastName: 'Smith' },
    { firstName: 'Bob', lastname: 'Smith' },
  ]);
};

const getFirstElement = (x) => {
  return x[0];
};

const getFullName = (user) => {
  return `${user.firstName} ${user.lastName}`;
};

const getFullNameOfFirstUser = R.pipe(
  getUsers,
  liftP(getFirstElement),
  liftP(getFullName),
);

const firstUserPromise = getFullNameOfFirstUser(); // Promise of a string

const firstUser = await firstUserPromise; // firstUser === 'Joe Smith'

I hope you find this solution helpful.