In Canto VI, we begin by reiterating the classic words:

When it comes to understanding someone’s core JavaScript skills as a whole, I’m most interested in how they use closures and how they take full advantage of async. — Jake Archibald

We talked a lot about closures in the last post, so you should know that what we’re going to talk about now is async.

  • Praise rich three generations, pay attention to beauty life! 👍 👍 👍 👍 👍 👍

Look at the asynchronous

Why do we find the “asynchronous problem” complicated?

One of the most important reasons is time! Time will be our operation of data, management, become a few orders of magnitude more complex!

Need to put forward in particular and clear is: asynchronous and synchronous can be converted to each other! Whether we use asynchronous or synchronous depends on — how to make the code more readable!

Functional programming provides the landing principle (reviewed many times) for “more readable code” :

  1. Strict control of display input and output;
  2. Encapsulate high-level functions, such as partial functions and currying to achieve time-domain separation of parameters;
  3. Encapsulate high-level functions, such as function assembly, to form black boxes;
  4. Encapsulate other basic methods, such as array manipulation;
  5. .

So we can expect asynchrony in functional programming!

Reduced time state

The code:

var customerId = 42; var customer; LookupCustomer (customerId, function onCustomer(custom record){var orders = customer? customer.orders : null; customer = customerRecord; if (orders) { customer.orders = orders; }}); LookupOrders (customerId, function onOrders(customerOrders){ customer) { customer = {}; } customer.orders = customerOrders; });Copy the code

onCustomer(..) And onOrders (..) Callbacks are two definitions, and the order in which they are executed is not determined, so it is a complex state based on time.

A callback function is a function that is passed as an argument to another function. When that function finishes executing, it executes the function that was passed.

  • How to determine the priority of their execution in time?

Usually, the first thing that comes to mind is to put lookupOrders(..) Wrote onCustomer (..) Inside, then we can confirm onOrders(..) In onCustomer (..) And then run.

Let me write it this way, right?

Wrong! Because onCustomer (..) , onOrders (..) The relationship between the two callbacks is more of a race (both assign customer.orders), and they should be executed in parallel, not serial.

I don’t care which one of you executes first. Whoever finishes first will be assigned the value of Customer.orders!

So the way we think about it is:

Check the external scope variable customer with the corresponding if-declaration in the respective callbacks. When the respective callback functions are executed, the state of the customer is checked to determine the order of execution. If the customer is not defined in the callback function, it is run first, otherwise it is run second.

However, this makes the code even harder to read!! Internal function assignments depend on external variables and are even influenced by external callback functions.

What was to be done?

Finally, we use the JS Promise to reduce this time state and turn asynchronous to synchronous:

var customerId = 42; var customerPromise = lookupCustomer( customerId ); var ordersPromise = lookupOrders( customerId ); customerPromise.then( function onCustomer(customer){ ordersPromise.then( function onOrders(orders){ customer.orders = orders; }); });Copy the code

Two. Then (..) Before running, lookupCustomer(..) And lookupOrders (..) Has been called synchronously, satisfying parallel execution, who finished first, who assigned to customer.orders, so we don’t need to know who came first!

In such an implementation, the concept of time sequence is no longer required! Reduced time status!! Code is more readable!!

Lazy array

Var a = [1,2,3] var b = a.map(v => v * 2); b; / / minus [2]Copy the code

This is an active array because they operate synchronously (instantly) on discrete immediate values or values on a list/structure of values.

What do you mean?

A maps to B, and then modify A, b will not be affected.

var a = []; var b = mapLazy( a, v => v * 2 ); a.push( 1 ); a[0]; // 1 b[0]; // 2 a.push( 2 ); a[1]; // 2 b[1]; / / 4Copy the code

And here, it’s an inert array, mapLazy(..) Essentially “listening” on array A, as soon as a new value is added to the end of the array (push(..)) ), it runs the mapping function v => v * 2 and adds the changed value to the array B.

What do you mean?

A maps to B, and you modify A, and B changes.

  • So why is the second one inert?

Turns out, the latter has the concept of asynchrony.

Let’s imagine an array that doesn’t simply get values, but an array that lazily receives and responds to (i.e., “reacts”) values, such as:

Var a = new LazyArray(); // release: var a = new LazyArray(); setInterval( function everySecond(){ a.push( Math.random() ); }, 1000); / / * * * * * * * * * * * * * * * * * * * * * * * * * * / / subscriber: var b = arjun ap (function double (v) {return v * 2; }); b.listen( function onValue(v){ console.log( v ); });Copy the code

The process of setting “lazy array” A is asynchronous!

B is the array after the map, but more importantly, B is reactive, so we add something like a listener to B.

We call the first half publishers and the second half subscribers.

You have to wonder: what’s the use of defining this lazy array? Here publisher, subscriber, and what is the meaning?

Here’s the answer:

  1. Just as a promise extracts the time state we worry about from a single asynchronous operation, the publish-subscribe pattern extracts (splits) the time state from a set of values or operations;

  2. We separate the [publisher] code from the [subscriber] code so that each code should do its own job. This organization of code can greatly improve the readability and maintainability of your code.

One more summary here: Time makes asynchrony more complicated, and the use of functional programming in asynchrony is to reduce or kill time.

Imagine that A can be bound to other events, such as user mouse clicks and keyboard keys, webSocket messages from the server, and so on.

In these cases, A doesn’t have to pay attention to her time state.

Var a = {onValue(v){b.onvalue (v); }}; setInterval( function everySecond(){ a.onValue( Math.random() ); }, 1000); / / * * * * * * * * * * * * * * * * * * * * * * * * * * / / subscriber: var b = {map (v) {return v * 2; }, onValue(v){ v = this.map( v ); console.log( v ); }};Copy the code

Here the relationship between [time] and [A and B] is declarative, not imperative.

Let’s go one step further and take B = A.m.ap (..) Replace b value (v) with b value (v), and try to avoid the logic of B in a, so that the separation of concerns is more!

This LazyArray is called An Observable! (Of course, it doesn’t just apply to the map method)

There are already a variety of library classes for Observables, Most notably RxJS and Most.

Take RxJS as an example:

Var a = new rx.subject (); setInterval( function everySecond(){ a.next( Math.random() ); }, 1000); / / * * * * * * * * * * * * * * * * * * * * * * * * * * / / subscriber: var b = arjun ap (function double (v) {return v * 2; }); b.subscribe( function onValue(v){ console.log( v ); });Copy the code

In addition, RxJS defines more than 100 methods that can fire only when a new value is added. It’s like an array. Each Observable method returns a new Observable, meaning they are chained. If a method is called, its return value should be returned by the input Observable and then fired into the output Observable, otherwise discarded.

Such as:

Var b = a.filter (v => v % 2 == 1); var b = a.filter (v => v % 2 == 1); var b = a.filter (v => v % 2 == 1); var b = a.filter (v => v % 2 == 1); .map( v = v * 2 ); B. scribe(function onValue(v){console.log("Next:", v); });Copy the code
  • Usually, the subscribe (..) Methods are called at the end of the chain

More about: RxJS

Stage summary

This article introduces asynchrony in functional programming.

The principle is this: For asynchronous temporal operations, the basic functional programming principle is to turn them into temporal applications. Reduce the time state!

Just as a promise creates a single future value, we can create a positive list of values instead of values like an inert Observable stream.

We’ve introduced the RxJS library, and there are more beautiful JS functional programming libraries to come!

(as the saying goes, the three sides of the good library selection, work very early!!)

Now Ben knows a bit: whether a language is functional or not depends on whether its core libraries are functional.

We may not be familiar with libraries like RxJS yet, but we are starting to value them more, use them more, and appreciate them more!!

Asynchronous, above.

Preview: The seventh (the end of the series) — Practice + library recommendation!

I am Nuggets Anthony, the public number [nuggets Anthony], input exposure output, technology insight life!!