Quick prototyping & playing with promises in one line

Rationale

Promises are one of my favorite features of all the ECMAScript standards and provide a clever way of dealing with asynchronous results that can either be resolved or rejected.

But sometimes, when the source-code is growing, it can…


This content originally appeared on DEV Community and was authored by Amin

Rationale

Promises are one of my favorite features of all the ECMAScript standards and provide a clever way of dealing with asynchronous results that can either be resolved or rejected.

But sometimes, when the source-code is growing, it can be tedious to work with, especially when error messages can be easily ignored.

If you don't care about the error messages, but rather the end result, you can provide a simple fallback value with this simple trick.

Context

Let's say you wanted to fetch the list of users from your API.

<!DOCTYPE html>
<html>
  <body>
    <script>
      "use strict";

      fetch("https://jsonplaceholder.typicode.com/users");
    </script>
  </body>
</html>

In this short example, we are using the Fetch API to ask our API for a list of users.

Of course, we need to deal with the success (resolved) and errors (rejected) cases.

<!DOCTYPE html>
<html>
  <body>
    <script>
      "use strict";

      fetch("https://jsonplaceholder.typicode.com/users").then(response => {
        return response.json();
      }).then(users => {
        console.log(users);
      }).catch(() => {
        console.error("Yep, no users.");
      });
    </script>
  </body>
</html>

In this particular example, we don't really care about the reason why it would reject, we simply want to provide a default value. We could do that in a more imperative way using an async function.

<!DOCTYPE html>
<html>
  <body>
    <script>
      "use strict";

      const main = async () => {
        let users = [];

        try {
          const response = await fetch("https://jsonplaceholder.typicode.com/users")
          users = await response.json();
        } catch {
          // ... discarded
        }

        console.log(users);
      };

      main();
    </script>
  </body>
</html>

Here we are using an async function to imperatively handle each step of our promise. And if it fails, we simply have our default value that will kick in when we log the result.

This works well and as intended, but this is a lot of work for so little. Plus, we are using a try-catch with the catch part that is being discarded and is pretty much useless.

Let's see if we can find an alternative to all of this.

Alternative

Since the await keyword is used on a promise, nothing can stop you from writing all the promise instructions in one line and provide a default value right away.

<!DOCTYPE html>
<html>
  <body>
    <script>
      "use strict";

      const main = async () => {
        const users = await fetch("...").then(response => response.json()).catch(() => []);

        console.log(users);
      };

      main();
    </script>
  </body>
</html>

Let's break this down real quick.

fetch("...");

This is our promise. Nothing fancy, it will just fetch our data as earlier.

.then(response => response.json())

This is the part where we handle any resolved value. This means that when the response can be turned into a JSON value, we will receive what's behind this call (here, the list of users).

.catch(() => []);

This is the part where we handle the error. Here we simply say that instead of logging anything, we simply return a default value. Here it is an empty array so that it becomes easy to work with our data even if the request fails.

fetch("...").then(response => response.json()).catch(() => []);

All of this is a single promise. This is important to understand because this is literally the heart of this technique. Because we have only one single promise here we are able to use what is coming next.

It will either reject and trigger the .then part, or fail and trigger the .catch part. You handled all possible cases in one line and whatever the outcome of the promise is, you know that you have a value for one or the other.

await fetch("...")...

Here we simply make sure that anything that is being done on this line with the promise should be blocking the function until the promise is either resolved (the list of users) or rejected (the empty array).

If we put this all together, this means that in one line, you can easily request data from an API, tell it how you want it to be (either JSON or Text), and provide a default value in case it fails to fetch the data.

And this lets you use a nice two-liner for requesting and displaying any data from an API.

const users = await fetch("...").then(response => response.json()).catch(() => []);
console.log(users);

Conclusion

This technique is very interesting because it lets you prototype things quickly, and even if you don't really need the error message.

If you are on a recent version of Node.js and using an ECMAScript Module, you can even leverage the new top-level await feature to make this a short little script.

$ npm install node-fetch
$ touch index.mjs
import fetch from "node-fetch";

const users = await fetch("https://jsonplaceholder.typicode.com/users").then(response => response.json()).catch(() => []);

console.log(users);
$ node index.mjs
[...] (output truncated)

Be aware that any error messages will be hidden and so this technique is not well suited in a large application where you want to have controls and monitoring about what failed, and possibly file error reports to a third-party application like Sentry.

Also, the goal of this technique is definitively not to be clear and readable, if you are concerned about these points, you should be writing your promises using the classic syntax instead.

And of course, this technique is only usable in environments that support writing async functions so be aware of that if you are not transpiling your code.


This content originally appeared on DEV Community and was authored by Amin


Print Share Comment Cite Upload Translate Updates
APA

Amin | Sciencx (2021-03-14T19:13:24+00:00) Quick prototyping & playing with promises in one line. Retrieved from https://www.scien.cx/2021/03/14/quick-prototyping-playing-with-promises-in-one-line/

MLA
" » Quick prototyping & playing with promises in one line." Amin | Sciencx - Sunday March 14, 2021, https://www.scien.cx/2021/03/14/quick-prototyping-playing-with-promises-in-one-line/
HARVARD
Amin | Sciencx Sunday March 14, 2021 » Quick prototyping & playing with promises in one line., viewed ,<https://www.scien.cx/2021/03/14/quick-prototyping-playing-with-promises-in-one-line/>
VANCOUVER
Amin | Sciencx - » Quick prototyping & playing with promises in one line. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/03/14/quick-prototyping-playing-with-promises-in-one-line/
CHICAGO
" » Quick prototyping & playing with promises in one line." Amin | Sciencx - Accessed . https://www.scien.cx/2021/03/14/quick-prototyping-playing-with-promises-in-one-line/
IEEE
" » Quick prototyping & playing with promises in one line." Amin | Sciencx [Online]. Available: https://www.scien.cx/2021/03/14/quick-prototyping-playing-with-promises-in-one-line/. [Accessed: ]
rf:citation
» Quick prototyping & playing with promises in one line | Amin | Sciencx | https://www.scien.cx/2021/03/14/quick-prototyping-playing-with-promises-in-one-line/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.