Lazy Functions Of JavaScript

Lazy Functions Of JavaScript Main Logo

Lazy Functions Of JavaScript!

Hi there!

I thought here to tell you about how you can create and use lazy functions in JavaScript using the Fluture library. This will be a brief overview of how to create functions, how to handle errors and a little bit about parallelism. Functional programming brains will not soar! I promise!

Fluture

Fluture is a library developed by Aldwin Vlasblom that implements Future. Future is an alternative to Promise, which has a much more powerful API that allows you to implement cancellation (cancellation), safe “recursion”, “error-free” execution (using Either) and another small cart of steep features.

I think it’s worth telling you about the methods (monads) that I will use in the examples below.

  • .of (Any) – creates Future from the passed value
  • .map (Function) – no, this is not Array.map, this is a transformation function, similar to Promise.then
  • .chainRej (Function) – similar to Promise.catch catches an error
  • .fork (Function, Function) – starts the execution of Future

Creating a lazy function

For myself, I highlighted two main approaches to creating lazy functions in Fluture. The first approach is that we create a function that accepts source data and returns the Future ready for execution. The second approach is that we create a Future with all the transformations described, and then transfer data to it.

Unclear? Let’s take an example! We have this function


<span class="hljs-keyword">const</span> multiply10 = <span class="hljs-function"><span class="hljs-params">x</span> =></span> x * <span class="hljs-number">10</span>;

Now make it lazy using the first approach.


const multiply10 = x => x * 10;

const lazyMultiply10 = (x) =>
Future
.of (x) // Create Future from value
.map (multiply10); // Now our function is here.

lazyMultiply10 (2) .fork (console.error, console.log);
// -> 20

Too cumbersome, isn’t it? Let’s try to write more succinctly, using the second approach.


const multiply10 = x => x * 10;
const lazyMultiply10 = Future.map (multiply10);
const value = Future.of (2); // wrapping our value in the future

lazyMultiply10 (value) .fork (console.error, console.log);
// -> 20

Now is better, but still cumbersome. It should be more compact!


const lazyMultiply10 = Future.map(x => x * 10);

lazyMultiply10(Future.of(2)).fork(console.error, console.log);
// -> 20

In fact, these approaches are not mutually exclusive and can be used together.


const lazyMultiply10 = Future.map(x => x * 10);

const someCalculation = a =>
Future
.of(a)
.map(v => v + 1)
.chain(v => lazyMultiply10(Future.of(v));

someCalculation(10).fork(console.error, console.log);
// -> 110

Error processing

Error handling in Future is practically the same as error handling in Promise. Let’s remember, let’s imagine a function that makes a request to a third-party, not very stable API.


const requestToUnstableAPI = query =>
request({
method: 'get',
uri: `http://unstable-site.com/?${query}`
})
.then(res => res.data.value)
.catch(errorHandler);

Same function, but wrapped in Future


const lazyRequestToUnstableAPI = query =>
Future
.tryP(() => request({
method: 'get',
uri: `http://unstable-site.com/?${query}`
}))
.map(v => v.data.value)
.chainRej(err => Future.of(errorHandler(err));

In fact, error handling can be made more flexible. For this, we need the structure of Either, and this is a little beyond the scope of my review.

Parallelism

To work with parallelism, Future implemented two methods race (Futures []) (similar to Promise.race), parallel (n, Futures []) and both (Future, Future), but it is a special case of parallel.

The parallel method takes two arguments, the number of concurrently executed Future and an array with Future. To make parallel behavior the same as the Promise. all method, you need to set the number of executables as Infinity.

Here, too, we will not manage without examples


const requestF = o => Future.tryP(() => request(o));
const parallel1 = Future.parallel(1);
const lazyReqs = parallel1(
[
'http://site.com',
'http://another-site.com',
'http://one-more-site.com',
]
.map(requestF)
);

lazyReqs.fork(console.error, console.log);
// -> [Result1, Result2, Result3]

Promise compatibility

In JavaScript from Promise, there is no way to go, and hardly anyone will be happy if your method returns some incomprehensible Future. For this, Future has a .promise () method, which will start the execution of the Future and wrap it in Promise.

Links

Here, perhaps, everything that we wanted to tell you. If the topic is interesting, let us know, we will tell you more about error handling.