What the heck is a 'thunk' and what's 'Currying' ?!
Tags: javascript, webdev, programming, frontend
Published: 2022-06-30 13:01:47

---
title: What the heck is a 'thunk' and what's 'Currying' ?!
published: true
date: 2022-06-29 16:31:07 UTC
tags: javascript, webdev, programming, frontend
canonical_url: https://thecodingcookbook.hashnode.dev/what-the-heck-is-a-thunk-and-whats-currying
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5p8xjthrzs8hd10zfkwn.png
---

I'm quite sure the first term you'd heard of terms like `Thunks` or `Currying` in programming, your reaction would have been something similar to this,

![What?](https://media.giphy.com/media/ghuvaCOI6GOoTX0RmH/giphy.gif)

Well, don't worry, I felt the same when I heard about these terms the first time especially from the programming aspect until I realized how useful they are!

Before we start, this blog post assumes that you have a basic knowledge of JavaScript and asynchronous programming using Promises and callbacks. Some knowledge about functional programming in JS would also be quite helpful to understand both these concepts better. **Thunks** along with **Currying** are quite useful concepts when it comes to **Functional programming** in JavaScript.

Let's dive deeper into these concepts and understand what they are, and how we can use them!

## All about `thunks` in JavaScript

We have been using **callbacks** in JavaScript almost everywhere for various use cases like **asynchronous programming** , **listening to events** , **handling errors** , and much more. Thunks basically _extend the capabilities of callbacks_ and are quite useful when it comes to async programming in JavaScript, though they are still quite useful in certain scenarios involving synchronous programming.

### What is a `thunk`?

A `thunk` is just a function that delays the computation of a value or some logic.

> The word "thunk" is a programming term that means "a piece of code that does some delayed work"

Rather than executing some logic _now, we can write a function body or code that can be used to perform the work later_. Many of you working with `React` probably know an awesome and plain simple library called `redux-thunk` which as the name suggests is based on thunks, and is useful while doing state management using `Redux`.

There are two perspectives in which you can use `thunks`: **synchronous** , and **asynchronous**.

### Synchronous way of using `thunks`

Let's talk about how you can use a **synchronous thunk** ,

```
const power = (base, exponent) => {
  return Math.pow(base, exponent);
};

// `power` function is evaluated
// and the result is returned immediately
console.log(power(99, 9)); // 913517247483640800

// This is a thunk
const powerThunk = () => {
  return power(99, 9);
};

// Returns the same result as calling the `power` function
console.log(powerThunk()); // 913517247483640800
```

In the above code snippet, `power` is a simple function that calculates the power of a no and returns the calculated value immediately. `powerThunk` is a **synchronous thunk** that delays this result until we call it. As you might have noticed, `powerThunk` uses the `power` function internally to calculate and return the calculated value.

The important part is that this thunk has become a wrapper around some particular state. In this case, it is a result of a potentially expensive operation. This pattern allows us to hide the internal details of the computation similar to the principle of [Encapsulation](https://www.sumologic.com/glossary/encapsulation/#:~:text=What%20does%20encapsulation%20mean%3A%20In,in%20the%20form%20of%20classes.) of the **Object Oriented Programming** paradigm.

Now let's talk about how you can use `thunks` from the async programming perspective.

### Async `thunks`

So how can we describe an **async thunk**? It's just a simple function that doesn't need any additional parameters except for a **callback function**. In the case of async thunks, we can introduce a delay to process a synchronous function like the `power` function from the previous example or use it to handle asynchronous API calls.

Let's have a look at both cases. We can modify the previous example for **synchronous thunk** to understand this better.

```
const powerAsync = (base, exponent, callback) => {
  return setTimeout(() => callback(Math.pow(base, exponent)), 1000);
};

// This is an async thunk
const powerAsyncThunk = (callback) => {
  return function () {
    powerAsync(99, 9, callback);
  };
};

// This async thunk now returns a function that 
// can be called later on to calculate power.
const calculatePower = powerAsyncThunk((result) => console.log(result));
calculatePower();
```

In the above code snippet, we modified the `power` function to `powerAsync` function that **fakes an asynchronous function** using `setTimeout` and takes an additional parameter `callback`. Now, our async thunk `powerAsyncThunk` delays the execution of `powerAsync` function by returning a function. This makes it really useful as we can now just call this function returned by `powerAsyncThunk` whenever we want in our code later on.

Now, let's talk about how we can deal with **asynchronous API calls** using **async thunks**.

```
const fetchCurrenciesData = (callback) => {
  fetch("https://cdn.jsdelivr.net/gh/fawazahmed0/currency-api@1/latest/currencies.json")
  .then(res => res.json())
  .then(res => callback(res));
}

// This is an async thunk
const asyncThunk = (callback) => {
  return function () {
    fetchCurrenciesData(callback);
  }
}

// This async thunk now returns a function that 
// can be called later on to fetch data from the API.
const fetchCurrencies = asyncThunk((res) => console.log(res));
fetchCurrencies();
```

The `fetchCurrenciesData` function makes an API call to fetch all the currencies of different countries and also takes a `callback` function as a parameter. The async thunk `asyncThunk` returns a function that can be called later on to fetch the data from the API whenever we want in our code.

The data after calling `fetchCurrencies` function looks something like this,

```
{
aave: "Aave"
ada: "Cardano"
aed: "United Arab Emirates Dirham"
afn: "Afghan afghani"
algo: "Algorand"
doge: "Dogecoin"
dop: "Dominican peso"
dot: "Dotcoin"
dzd: "Algerian dinar"
egld: "Elrond"
egp: "Egyptian pound"
enj: "Enjin Coin"
eos: "EOS"
ern: "Eritrean nakfa"
etb: "Ethiopian birr"
ils: "Israeli New Shekel"
imp: "CoinIMP"
inj: "Injective"
inr: "Indian rupee"
iqd: "Iraqi dinar"
irr: "Iranian rial"
isk: "Icelandic krna"
jep: "Jersey Pound"
jmd: "Jamaican dollar"
jod: "Jordanian dinar"
jpy: "Japanese yen"
kava: "Kava"
kcs: "Kucoin"
kda: "Kadena"
kes: "Kenyan shilling"
...
}
```

### Where exactly are `thunks` used? 💡

Now that you have learned quite a lot about thunks, you might be wondering where exactly are **thunks** used.

- **Promises** in JavaScript are based on the concept of **thunks** and under the hood it uses thunks. Have a look at this [video](https://youtu.be/EhyuWntGA8s) which talks about how **thunks** can be used to sequence async function calls.

- The [redux-thunk](https://github.com/reduxjs/redux-thunk) middleware widely **uses thunks internally**. This enables us to use **thunks** with async logic inside, that can **interact with a Redux store's** `dispatch` and `getState` methods for React apps using **Redux** for state management.

## All about **Currying** in JavaScript

Let's look at another quite useful concept within functional programming in JavaScript.

![Let's do this!](https://media.giphy.com/media/BpGWitbFZflfSUYuZ9/giphy.gif)

**Currying** is an advanced technique for working with functions. Its used not only in JavaScript but in other languages as well!

### What is **currying**?

> **Currying** is a transformation of functions that converts a function from callable as `f(a, b, c)` into callable as `f(a)(b)(c)`.

We are transforming the function by breaking it down in such a way that it can be called in a step-by-step manner instead of calling it with all the arguments immediately. This technique is very useful, particularly when you don't have access to all the required parameters at an instant to be able to execute the logic inside your function.

Let's look at an example to understand this better. Suppose, we create a simple function `multiplyTwoNos` that multiplies two nos and returns the calculated value.

```
const multiplyTwoNos = (no1, no2) => {
  return no1 * no2;
};

console.log(multiplyTwoNos(3, 5)); // 15

// A curried function to multiple two nos
const curriedMultiplyTwoNos = function (no1) {
  return function (no2) {
    return no1 * no2;
  };
};

console.log(curriedMultiplyTwoNos(3)(5)); // 15
```

In the above code snippet, `curriedMultiplyTwoNos` is a function that uses **currying** to transform `multiplyTwoNos(3, 5)` function call to a function call something like this - `curriedMultiplyTwoNos(3)(5)`. The output is basically the same, but **currying** gives us more flexibility to calculate the multiplication of two numbers whenever we have access to both the numbers.

### Advanced Currying Implementation

Now, let's have a look at a bit more **advanced implementation** of **currying** for multi-argument functions. We'll first create a generic **currying** function and then use the above example of multiplying some numbers and getting the calculated value.

```
// A function that takes a callback function `func` 
// that defines the kind of operation/calculation that will be curried

const curry = function (func) {
  return function curried (...args) {
    // Ensure that we apply the operation defined by `func` 
    // with the max number of arguments supported by `func`.

    if(args.length >= func.length) {
      return func.apply(this, args);
    } else {
      // If number of parameters are insufficient to call `func` to 
      // perform the operation, recursively call `curried` with previously passed
      // parameters as well as new parameters. 
      return function (...args2) {
        return curried.apply(this, args.concat(args2));
      }
    }
  }
}
```

There are a lot of things happening in the above code! 😅 ![Overwhelmed!](https://media.giphy.com/media/NRXleEopnqL3a/giphy.gif)

But, don't get overwhelmed by seeing the above code, it's actually quite straightforward! Let's see how it works with an example and then we'll understand it properly.

```
const multiplyThreeNos = (no1, no2, no3) => {
  return no1 * no2 * no3;
};

let curriedMultiplication = curry(multiplyThreeNos);

console.log(curriedMultiplication(4, 5, 6)); // 120, still callable normally
console.log(curriedMultiplication(4)(5, 6)); // 120, currying of 1st arg
console.log(curriedMultiplication(4)(5)(6)); // 120, full currying
```

The result of `curry(func)` call is the wrapper `curried` that looks like this:

```
function curried(...args) {
    // Ensure that we apply the operation defined by `func`
    // with the max number of arguments supported by `func`.

    if (args.length >= func.length) {
      return func.apply(this, args);
    } else {
      // If number of parameters are insufficient to call `func` to
      // perform the operation, recursively call `curried` with previously passed
      // parameters as well as new parameters.
      return function (...args2) {
        return curried.apply(this, args.concat(args2));
      };
    }
  };
```

In the above code, we are using some of the concepts like [rest parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters), **Recursions** , and [.apply()](https://www.freecodecamp.org/news/understand-call-apply-and-bind-in-javascript-with-examples/).

There are basically two branches of code out of which one of them could get executed within the `curried` function because of the `if` statement.

- If the number of arguments passed to `curried` is **greater than or equal to** the no of arguments defined for `func`, then just pass the call to `func.apply(this, args);` which will execute ignore the extra arguments passed if any.

- Else if the no of arguments passed to `curried` is less, then we recursively call `curried` with **previously passed arguments** as well as the **new arguments** by using the `.concat()` method until the number of arguments for `curried` is not sufficient as per the definition of `func`.

> **Note** : **Currying** requires the function to have a **fixed number of arguments**. A function that uses rest parameters, such as `f(...args)`, cant be curried this way as implemented above.

### When and Why to use **Currying**? 💡

Currying can be useful for:

- Currying can be used when you want to create a function that will receive only single arguments or will receive arguments later on in your code.
- It can be used to trigger event listeners.

Let's look at some of the reasons why you may need to use Currying:

- Currying provides a way to make sure that your function receives all the arguments before you proceed with executing the core logic of your function.
- It divides your function into multiple smaller functions that can handle one responsibility. This makes your function pure and less prone to errors and side effects.
- It is used in the functional programming paradigm to create [higher-order functions](https://dmitripavlutin.com/javascript-higher-order-functions/).

## Conclusion

In this blog, we learned about **Thunks** & **Currying** , some of the most useful yet a bit advanced concepts of functional programming in JavaScript. We talked about **thunks** in detail like what are **thunks** , how can you use them, when to use them, and where are they used. Similarly, we learned about **Currying** , how to implement **currying** , **advanced implementation** of **currying** , and when to use it.

That's it from me folks, thank you so much for reading this blog! 🙌 I hope this blog was helpful and gave you an insight about **Thunks** & **Currying** and how you could use these very useful concepts of the functional programming paradigm in your JavaScript apps 😄

Before we end, ![Excelsior!](https://media.giphy.com/media/d3yvDeQ9fES0JTfG/giphy.gif)

> Feel free to reach out to me:
> [Twitter](https://twitter.com/DevanshYtweets)
> [Linkedin](https://www.linkedin.com/in/devansu-yadav/)
> [GitHub](https://github.com/Devansu-Yadav)