DEV Community

Cover image for Returning A Promise From A JavaScript Function Is Useful
Josh Pollock
Josh Pollock

Posted on • Edited on

Returning A Promise From A JavaScript Function Is Useful

One JavaScript feature that has tripped me up a bit recently is the difference between a function that returns a promise and a function that returns the value of that the promise resolves. Decoupling data fetching helps with server-side rendered apps and can also make mocking a remote API in tests easier. In my case, I wanted to use the same functions for getting data into a static file generator as I used in the React client.

In the past, I always wanted to return the result of the API call. The more that I understand the subtle difference between returning a promise and returning the result of the the promise, the more I prefer to return a promise. In this post, I will show to return a promise from an asynchronous function, with and without explicitly creating a Promise object with the new keyword. More importantly, I'll cover when and why this pattern is useful when working with remote APIs.

This is a quick post and I assume you are somewhat familiar with using async and await in JavaScript. I wrote in more detail about that here.

What Is A Promise?

If you are not familiar with promises, I recommend reading MDN first. A useful definition for this article, would be to say it's a function that promises to do something and then let's you do something with it.

The kinds of functions we're talking about are considered "thenable". We are able to call the function "then()" on there results.

Fetch is an example of a "thenable". This example makes a remote HTTP request and then console.logs the response.

fetch(url).then(r => console.log(r) )
Enter fullscreen mode Exit fullscreen mode

Returning A Promise From A Function

There are a few ways to return a promise from a function. One way is to use an async closure that returns a thenable function. This example gets a page of posts from a WordPress site:


function async fetchPosts(page = 1){
    // Await fetch of posts
    const posts = await fetch( `https://site.com/wp-json/wp/v2/posts?page=${page}` )
    // Return posts
    return posts;
}
Enter fullscreen mode Exit fullscreen mode

We can add a promise chain in this closure for repetitive logic. For example, parseing the response from JSON to an object:


function async fetchPosts(page = 1){
    // Get posts
    const posts = await fetch( `https://site.com/wp-json/wp/v2/posts?page=${page}` )
    //Then parse
    .then( r => r.json() );
    // Then return object
    return posts;
}
Enter fullscreen mode Exit fullscreen mode

This example is probably more useful then the first one. This pattern is useful when we want to consume this function in a closure that can not be async. For example:

React.useEffect( () => {
    //Fetch posts, THEN update state
    fetchPosts(page).then(posts => setPosts(posts) );
},[page]);
Enter fullscreen mode Exit fullscreen mode

Keep in mind, this is a function that returns a promise to make an API request. Not a function that makes an API request. That means that calling then() triggers the request. Another way to do it is to use Promise.all()

//Get page 1 and page 2 of posts:
Promise.all([ fetchPosts(1), fetchPosts(2) ] ).then( posts  => {
  const page1 = posts[0];
  const page2 = posts[1];
});
Enter fullscreen mode Exit fullscreen mode

Using The Promise Constructor Inside An Async Closure

The other way to return a promise from a function is to instantiate a promise object, and return it. This lets us manually call the resolve and reject functions.

We can use this to add a caching layer to our fetchPosts() function. The function can resolve immediately, if the page of posts is in the cache:

let cache = {};
function async fetchPosts(page = 1){
   return new Promise( asnyc (resolve, reject) => {
       //Is post in cache?
       if (cache.hasOwnProperty( page) ){
           //Resolve from cache right away
           resolve( cache.page );
       } 
       //Make request
       const posts = await fetch( `https://site.com/wp-json/wp/v2/posts?page=${page}` ).then( r => r.json() );
       //cache for next call.
       cache[ page ] = posts;
       //now resolve
       resolve( posts );
   });
});

Enter fullscreen mode Exit fullscreen mode

I Promise This Is Useful

In this post, I showed how to return a promise from an asynchronous JavaScript function.

I find this to be a useful pattern when abstracting API calls from UI or other business logic. What I like is that it leaves the responsibility of when to call the function to the module consuming it.

Featured Image: Photo by Agnes Gospodinova on Unsplash

Top comments (1)

Collapse
 
andrej_gajdos profile image
Andrej Gajdos

I am 100% sure the last snippet doesn't work. function async, asnyc, etc