Showing posts with label promise. Show all posts
Showing posts with label promise. Show all posts

Sunday, March 5, 2023

What's wrong with eager evaluation? (And why you should use fp-ts/Fluture for that)

Eager evaluation in JavaScript Promises can lead to several problems. Eager evaluation means that a Promise's executor function is executed immediately when the Promise is created, rather than when it is needed later on. Here are some potential issues with eager evaluation:

Increased resource usage: If the Promise's executor function performs a resource-intensive operation, eager evaluation can cause unnecessary resource usage. For example, if the Promise is used to fetch data from a server, eager evaluation would mean that the fetch operation is performed immediately, even if the data is not needed until later.

  • Unnecessary blocking: If the Promise's executor function performs a blocking operation (such as a long-running loop), eager evaluation can cause unnecessary blocking of the main thread. This can lead to unresponsive user interfaces and other performance issues.
  • Wasted work: If the Promise's executor function performs work that is not needed (for example, if it fetches data that is never used), eager evaluation can result in wasted work and unnecessary network traffic.
  • Race conditions: Eager evaluation can also lead to race conditions, where multiple Promises are created but only one of them is needed. This can result in unnecessary resource usage and can make code harder to reason about.

To avoid these problems, it's generally better to use lazy evaluation with Promises. In lazy evaluation, the Promise's executor function is only executed when the Promise is needed (for example, when it is passed to a then() method or when it is awaited in an async/await function). This approach allows for more efficient use of resources and can help prevent performance issues.

The fp-ts library provides several abstractions and functions that can help avoid the problems associated with eager evaluation in Promises. For example, the type Task is essentially a Promise wrapped in a function, allowing you to control when it's executed, therefore it's considered "lazy".

import { task } from 'fp-ts/lib/Task'

const fetchTask = task(() => fetch('https://example.com/data'))

If you call fetchTask(), only then will your HTTP call be executed.

Fluture

There are also other viable options, like Fluture, which is a Future implementation in Javascript. I'm not aiming to discuss Future-s here, but it might be mentioned, that it is a monadic interface that is lazy by it's nature - in a way it's similar to Promise, but more functional, with it's advantages.

Saturday, April 10, 2021

Conditional Promise.all

Have been in a situation where you needed to dynamically shoot out HTTP requests based on some branching logic? Are you using a Promise based HTTP client library like fetch or axios?

Fear not, here is a solution for your needs!

In general the solution is based on coming up with an interface that's not only returning the data when the Promise was resolved, but also give a companion flag that identifies the promise it was initiated from.


You can find the idea on this SO post as well.

Thursday, January 23, 2020

My current favourite trick in Node.js

At my current job I need to work a lot with Node.js backend services, and one thing is recurring - I need to simulate some delays in the code, mostly for testing purposes.
In the old days this was pretty problematic, we had the classic "callback hell", which made the code very unreadable, sometimes had to refactor (copy-paste mostly) huge parts of the codebase, just to simulate some delay.
Nowadays the air is more fresh regarding asynchronous programming in the JavaScript economy, because we have Promises supported natively, and in newer versions of Node.js you get async-await, which we learned about in one of my previous posts (don't get fooled, the post is about the package `co`, which was essentially the equivalent of today's async-await).
So how do we simulate delays today? It's super easy actually, you just need to know that async-await is basically operating on top of Promises. Without any further discussion, here is the code:

await new Promise(resolve => setTimeout(resolve, 5000));

Let's look at what this codesnippet does.
await is going to wait (no pun intended) for a Promise, and until it resolves, it's not going to continue the execution flow.
So we create the Promise, where we just wait using the setTimeout method 5000 milliseconds (5s), and then resolve the Promise! Simple as that!
I think this is a pretty handy codesnippet, that I wish I knew before!

Wednesday, July 6, 2016

Demistfying co

I always wondered why generator functions are included in the JS language, and still don't see why they are very powerful. However one of the key reasons I still think they are a needed step for the evolution of the language is the use-case of this very article.
I am not going to talk about generator functions or Promises or the Fetch API in this article, but you can read for more information in the links I attached.
The following code snippet is basically what co package does where you can easily do asynchronous calls in a synchronous way. (the key difference here is co can deal with not only Promises, but here we just wanted to work with them, not like e.g. thunks, which co can handle).
Enough with the chit-chat, let's see some code!
The first thing what you should feel here is it has a synchronous feeling when it does something asynchronous. Witchcraft!
Let's see what is happening here (click on "Next" and "Prev" to follow the steps of the control flow)



See the Pen Demistifying co by Adam Nagy (@nagyadam2092) on CodePen.
I think this whole topic is more about to move on to the next generation asynchron call methodology, which is called async-await and thus it is a needed step to be able to build that kind of behaviour.
BTW it's fun to have a look at what an ES6 transpiler is doing with this code-snippet, go on and try it here: https://babeljs.io/repl/
In summary I think we achieved a good (not great) way of handling asynchronous calls with a "synchron-like" feeling.