We use cookies and other tracking technologies to improve your browsing experience on our site, analyze site traffic, and understand where our audience is coming from. To find out more, please read our privacy policy.

By choosing 'I Accept', you consent to our use of cookies and other tracking technologies.

We use cookies and other tracking technologies to improve your browsing experience on our site, analyze site traffic, and understand where our audience is coming from. To find out more, please read our privacy policy.

By choosing 'I Accept', you consent to our use of cookies and other tracking technologies. Less

We use cookies and other tracking technologies... More

Login or register
to apply for this job!

Login or register to start contributing with an article!

Login or register
to see more jobs from this company!

Login or register
to boost this post!

Show some love to the author of this blog by giving their post some rocket fuel 🚀.

Login or register to search for your ideal job!

Login or register to start working on this issue!

Engineers who find a new job through Golang Works average a 15% increase in salary 🚀

Blog hero image

Building your own `promises` in NodeJs

Narasimha Mujumdar 19 April, 2020 | 4 min read

One way to understand the promises functionality of NodeJs is to try and attempt to build a function which behaves like one. As a programming exercise it is fun and a good challenge to implement our own promise like functionality.

In this article I will explain the version I came up with up. It makes use of recursion and also uses some of the concepts of functionals programming.

How will the clients use our promise function?

The first step is determine the interface of our promise function. We want our clients to be able to perform something like this:

Let us consider a simple example: 1.png

function promise is our home-grown equivalent of

new Promise((resolve,reject)=>{...})

Our client would want to use the result of our promise and would want to chain a list of functions and a function to handle error.

Note that the function addX is a higher-order function, its a function that returns another function.

In order to simplify the implementation let us define the interface in the following manner:

Functionally it is similar to the then,catch chainof functions. Possibly it is a bit cleaner because we can now supply an array of functions which are applied serially. We can also supply the error handler as a seperate function.

Having defined this interface for our clients, let us attempt to implement it.

Version 1 of implementation

3.png

promise can be defined as a function takes a function fn and returns an object, which has a
function called pipe defined in it.

The pipe function as discussed takes an array of functions to invoke when the result is resolved and error handler to invoke if there is rejection (in case of an error).

The function fn is passed by the client when it creates a new promise. It is a function that needs to be passed with two parameters: a resolve function, which the client invokes it wants to resolve a result and a reject function which it will invoke it wants to reject the promise invocation.

When the resolve is invoked by the client code, we want to get the result and pass the result through the pipeline of functions setup earlier by the client:

resolve → result → invoke add1 → result → invoke add2 → result → invoke show

The result of the resolve has to passed to add1, whose result we pass it onto add2 and its result is passed onto show.

This provides us a clue on how to implement our promise function. For the sake of simplicity let us ignore promise rejection and focus only on promise resolution.

We want to trigger promise resolve (or reject) by invoking fn function supplied by the client. But we want to capture result that is resolved and then pass the result to the pipeline of functions

We could use javascript reduce function on array of functions to process the result: 4.png

This works and shows the result of 203. The complete code is given below:

const promise = (fn) => {
  return {
    pipe: (functions, errHandler) => {
      fn((result)=>{
        return functions.reduce((acc,f)=>{
          return f(acc)
        },result)
      })
    }
  }
}


const compute = (input) => {
    return promise((resolve,reject)=>{
      setTimeout(()=>{
        resolve(input * 2)
      },1000)
    })
}
const addX = (x) => {
  return (result)=>result+x
}
const show = (result) => {
  console.log(result)
}
const handleErr = (err) => {
  console.log("Error: ", err)
}
compute(100)
.pipe([
  addX(1),
  addX(2),
  show
])

There is one issue with this implementation. Any promise library worth its salt allows chaining of promises. What this means it allows the functions in the pipeline to return promises: 5.png

I have changed the definition of addXIt is now a function that returns a function which returns a promise instead of the result.

As expected the promise implementation breaks. It is returning the promise directly instead of waiting to resolve it. The implementation of promise should be evaluating any intermediate results that turn out to be promises instead of results.

Thus: 6.png

This hints that we could follow this approach:

We check the result of a function in the pipeline, if it is a promise, we want invoke pipe
function of the returned promise, and passing the remaining functions in the pipeline as
functions parameter.

Importantly we want to break the reduce loop to be able to invoke the pipe function of promise returned as an intermediate result.

We can no longer use reduce for our implementation as it does not allow breaking the loop. We could use a for loop, but keeping in line with our functional programming approach, let us define a recursive function to loop.

7.png

We have redefined the pipe implementation to use recursive function called loop to loop.

Note the use of ES6 array destructing feature to obtain the the first function in the array as f and the remaining elements as fs: const [f,...fs] = functions

Now that we are looping instead of using reduce we should be able to stop the loop and invoke pipe on the returned promise (if the intermediate result is a promise): 8.png And doing that works!

The result is returned after 3 seconds as expected (compute — resolves after 1 sec, and both addX functions also resolve after a second each).

Now the only thing that remains to be addressed is the error handling:

We need to re-introduce the errHandler parameter to pipe function. When we invoke fn function provided by the client, we need pass a reject function as well so that client can invoke it wants to reject the promise invocation. Addressing these two points give us the following code: 9.png

Note that I am setting a default error handler if in case the error handler is not passed by the client.

We started with an interface of our choice for our promise library and we implemented it using some of the concepts of functional programming and some recursion.

Two part video about the same topic: https://youtu.be/oK0s8Nq3r90

Originally published on medium.com

Author's avatar
Narasimha Mujumdar
    Go
    JavaScript
    C#
    Haskell
    Rust

Related Jobs

Related Issues

viebel / klipse-clj
viebel / klipse-clj
  • Open
  • 0
  • 0
  • Intermediate
  • Clojure
viebel / klipse
  • Open
  • 0
  • 0
  • Intermediate
  • Clojure
viebel / klipse
  • Started
  • 0
  • 1
  • Intermediate
  • Clojure
  • $100
viebel / klipse
  • 1
  • 0
  • Intermediate
  • Clojure
viebel / klipse
  • Open
  • 0
  • 0
  • Intermediate
  • Clojure
  • $80
viebel / klipse
  • Open
  • 0
  • 0
  • Advanced
  • Clojure
  • $80
viebel / klipse
  • Started
  • 0
  • 2
  • Advanced
  • Clojure
  • $180
viebel / klipse
  • Open
  • 0
  • 0
  • Intermediate
  • Clojure
viebel / klipse
  • Started
  • 0
  • 2
  • Intermediate
  • Clojure
  • $80

Get hired!

Sign up now and apply for roles at companies that interest you.

Engineers who find a new job through Golang Works average a 15% increase in salary.

Start with GithubStart with Stack OverflowStart with Email