The benefit of the Thenable object in JavaScript

Babak Gholamzadeh
Jan 11 · 5 min read

The relation between thenable object, promise and async/await

The benefit of thenable object in JavaScript
The benefit of thenable object in JavaScript

If you use libraries like mongoose, knex and some others similar to them — which has kind of chainable methods and also runs asynchronously — you should read this article too.

You might have already heard about thenable object, promise and async/await. If you haven’t or still didn’t get the relation between them, don’t worry we will cover that here completely.

What is “thenable” object?

The definition of thenable object is the simplest thing in the world:

For Example:

This object (obj) is a thenable object.

Note: A thenable object is allowed to have any other property and method with any name as well, but it must have a method is named then to be a thenable object.

The relation between “thenable” object and “promise”?

Simply every promise object is just a thenable object, because it has a then method (which is used to access the result of a settled promise). That’s it.

But keep in mind that this relation is not the other way around, which means that every thenable object is not a promise object.

The relation between “thenable”, “promise” and “async/await”

The then keyword is just a convention that has been defined to make life easier.

For instance, now we all know to access the result of a promise, we should call the then method of it. The name is not exec, run, get, map or anything else that causes confusion.

This naming convention has also helped us to have async/await syntax in JavaScript. But how?

Look that the code below and see the magic:

If you are not familiar with IIFE function check this article.

You probably have already used async/await syntax in your codes and know how to used it.

But do you also aware that how async/await works?

We are not going to fully cover the behind of the scene of async/await here. However, if you are curious about it (and you should be), you can check this article out to get the main idea of how it works.

Brief explanation of how “async/await” works

You should know that whenever you put an await keyword before any function (object), JavaScript just tries to call the then method of that object.

Also because async/await syntax is implemented by generator function and await keyword is exactly used instead of yield keyword, so the async function needs to be resumed after calling the then method. In order to handle this operation, async function also sends a callback to the then method as a parameter that contains the functionality for resuming itself.

I know it sounds a little bit fuzzy and for getting the idea better, you should check out this sample code:

You can run this code and see the result yourself.

If you look at the output, you can see that almost everything works as expected. But we still don’t have the result of the last console.log(‘end’) and the operation is kind of freezing in that point.

The reason of this freezing is because the callback function which has been sent to the then method has not been called yet to resuming the async function.

In order to solve the problem, we should just call the callback to continue the operation.

Also if you send any value to the callback as its parameter, you will get it by the await keyword (see the code below):

And now everything worked perfectly.

Main subject

I guess till here you got the idea of what we are talking about and you might find out that how mongoose, knex and some other libraries work with some tweaking the code.

As a reminder, these libraries can be chainable and whenever you put an await keyword in behind of them or call the then method in their chain, they work exactly like a promise object.

In the following we are intending to walk through a simple example of a chainable object that would be ran by await keyword and/or then method.

The functionality that we expect from this stupid example that we are going to implement is to have some simple math methods (i.e. add, sub, mul, div) and whenever we use it with await keyword, it would run the main asynchronous operation and returns the corresponding result (which can be fulfilled or rejection).

The main asynchronous operation would be fulfilled if the reminder of the final value is divided by 2 be greater than zero — or not equal to zero (n % 2 !== 0) — and otherwise it would be rejected.

Now we have an asynchronous function, let’s implement another simple function which can be chainable.

Note: I just refuse to use this keyword here to avoid confusion that some people might have with it.

Now this function (mathOp) can be used in this way:

It’s time to get to the main point and add the magical then method to this chainable object and run the asyncFunction inside of it. Afterward just return the result of it (which is a promise object).

Reminder: Don’t forget the callback function is going to be sent by await keyword automatically.

This is the whole implementation of the then method. It is simple, isn’t it?

Let’s put it inside the op object:

And now you can run the code below to see the result:

Up until now it sounds that it works perfectly, but let me remind you that we didn’t handle the error that is caused by the rejection state of the asyncFunction.

First of all, to handle the errors, we need a catch method beside of the then method as well.

Put this method next to then method inside of op object.

There is nothing special about catch method and we just added it that we could use it on chaining methods ourselves — which works like then method on chaining and also send the callback to the catch method on the returned promise object.

In the next step for handling errors we need to tweak our then method.

If you wonder why we need to change the then method to handle the errors and what is the relation between them, let me tell you another secret of async/await.

I have to admit that I already lied to you about that await keyword that I said it just sends one callback on calling the then method, I’m sorry about that guys, because it sends two callbacks.

As a reminder we should mention that the then method on promise object takes two callbacks, but the second one is arbitrary which is used as a callback for catching errors — just like catch method.

If you are curious about how promise works, you should check out this book.

If you change the then method body like the code below, you would see the same output as below:

Great! Now we can also use mathOp function with await keyword inside of a try/catch block to handle the errors.

We are done with handling errors and the whole functionality of our stupid example.

At the end we can also do some fancy stuff to have a little cleaner code.

Wrapping up

I hope you found this article useful.

If there is any unclear or ambiguous part, please feel free to ask your questions in the comment section or you can send me message directly.

JavaScript In Plain English

New JavaScript + Web Development articles every day.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store