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.