npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

tryumph

v1.2.2

Published

Bring the "Umph" to the javascript's async error handling

Downloads

23

Readme

tryumph

GitHub License Test Coveralls branch Documentation

Bring the "Umph" back to the JavaScript error handling!

What is it?

  const result = await try$(itMayThrow(a, b, c));
  result.match(
    when(Ok, consumeResult),
    when(Err, handleError)
  );

Or even better, You can use the .dwait function call on the returned promise of try$ to get a DeferredPromise built using dwait library:

  const result = await try$(itMayThrow(a, b, c)).dwait().match(
    when(Ok, consumeResult),
    when(Err, handleError)
  ).await;

With the use of DeferredPromise we can keep chaining functions instead of awaiting each result, And we can defer all awaits to the last operation.

Does that seem too Rusty to you? What about something like this? Let's Go!

  const [res, err] = await try$(itMayThrow(a, b, c));
  if (!!err) {
    handleError(err);
    return;
  }
  consumeResult(res);

You may say these are all async, What about sync operations? Here are the examples above but this time as sync functions.

  const result = tryFn$(itMayThrow, a, b, c);
  result.match(
    when(Ok, consumeResult),
    when(Err, handleError)
  );

Or

  const [res, err] = tryFn$(itMayThrow, a, b, c);
  if (!!err) {
    handleError(err);
    return;
  }
  consumeResult(res);

But Why?

We all have been in places where we want to get some result from a function that can throw, This is especially true for async functions since we usually need async operations to handle IO. So let's take a look at this example:

axios
  .get("/user/12345")
  .then((result) => consumeResult(result))
  .catch((error) => handleError(error));

It is the snippet of code from the ErrorHandling section of axios library. So what about async/await? If we want to handle the errors properly with the async/await pattern we have to write it inside a try/catch block like this:

  try {
    const resp = await axios.get("/user/12345");
    consumeResult(resp);
  } catch (err) {
    handleError(err);
  }

That is still not that bad, Right? What if we want to handle errors by using a default value instead of canceling the operation? Now we have to rewrite our code like this:

  let user = null;
  try {
    user = await axios.get("/user/12345");
  } catch {
    user = defaultUser;
  }
  consumeResult(user);

How about when we would like to load some additional data based on the first request? So let's modify the code above to load the user avatar too.

  let user = null;
  let avatar = null;
  try {
    user = await axios.get("/user/12345");
    avatar = await axios.get(user.avatarImage);
  } catch {
    if (!user) {
      user = defaultUser;
    }
    if (!avatar) {
      avatar = defaultAvatar;
    }
  }
  consumeResult(user, avatar);

As you can see it really easily gets out of hand... So let's rewrite it using tryumph!

  const userResult = await try$(axios.get("/user/12345"));
  const user = userResult.unwrapOr(defaultUser);
  const avatarResult = await try$(axios.get(user.avatarImage));
  const avatar = avatarResult.unwrapOr(defaultAvatar);
  consumeResult(user, avatar);

Much cleaner huh? tryumph borrows heavily from Rust and Go error handling to provide a more sane way for keeping errors under control!

Documentation

You can read the documentation over here.

More examples

What is in Result?

  const a = await try$(itWillBeFine());
  console.log(result.isOk()); // true
  console.log(result.isErr()); // false
  console.log(result.ok()); // "Result"
  console.log(result.error()); // undefined
  console.log(result.unwrap()); // "Result"
  console.log(result.unwrapOr("Default")); // "Result"
  const b = await try$(itWillThrow());
  console.log(result.isOk()); // false
  console.log(result.isErr()); // true
  console.log(result.ok()); // undefined
  console.log(result.error()); // "Error"
  console.log(result.unwrap()); // CRASH!! it will throw the error!
  console.log(result.unwrapOr("Default")); // "Default"

Here is another sync example

  const sum = (a, b) => a + b;
  const [res, err] = tryFn$(sum, 1, 2);
  if (!!err) {
    handleError(err);
    return;
  }
  consumeResult(res);