原文: https://codewithstyle.info/deep-dive-pipe-function-rxjs/

------------------------------------------------------------

Version 5 of RxJS introduced the concept of lettable (also known as pipeable) operators. Version 6 went one step further and deprecated the old way of calling operators (method chaining). You might have already used the pipe function. But do you really understand what it does?

Composing functions

RxJS is often called a functional-reactive programming library. It should not come as a surprise that you will find many functional programming inspirations in it. One of them is the pipe function. Take a look at the below piece of code:

const getElement = 
(id) => document.getElementById(id); const getValue =
(element) => element.value; function logElementValue(id) {
const el = getElement(id);
const value = getValue(el);
console.log(value);
}

The logElementValue function takes an id and logs to the console the value of the element with provided id. Can you see a pattern in this function’s implementation? Firstly, it calls getElement with id and stores the result in el. Next, the result is passed to getValue which produces a new result, el. Finally, el is passed to console.log. What this function does is simply taking the result of a function and passing it as an argument to another function. Is there a better, more concise way to implement this function? Let’s say we just have two functions (getElement and getValue). We will implement a generic function called compose that will pass the result of getElement to getValue.

const compose = (f, g) => x => g(f(x));

The definition is very simple but may take a moment to parse. We’ve defined a function that takes two functions f and g (that would be getElement and getValue in our case) and returns a new function. This new function will take an argument, pass it to f and then pass the result to g. That’s exactly what we need! Now I can rewrite logElementValue:

function logElementValue(id) {
const getValueFromId = compose(getElement, getValue);
const value = getValueFromId(id);
console.log(value);
}

How about more than two functions?

But, wait! Once we have the result of calling getValueFromId we immediately pass it to console.log. So it’s the same pattern here. We could write it like this:

function logElementValue(id) {
const getValueFromId = compose(getElement, getValue);
const logValue = compose(getValueFromId, console.log);
logValue(id);
}

But life would be much simpler if compose could take any number of functions. Can we do this? Sure:

const composeMany = (...args) => args.reduce(compose);

Another brain teaser! composeMany takes any number of functions. They are stored in args array. We reduce over args composing every function with the result of composing previous functions. Anyway, the results is a function that takes any number of functions and will pass the result of N-th function to (N+1)-th function. But what have we achieved by that?

function logElementValue(id) {  
const logValue = composeMany(getElement, getValue, console.log);
logValue(id);
}

Which can be simplified even more:

const logElementValue = composeMany(getElement, getValue, console.log);

Isn’t that cool? We have significantly simplified the code. It’s now very clear what logElementValue does. And by the way - composeMany is just a name a came up with. The official name is pipe!

const logElementValue = pipe(getElement, getValue, console.log);

Back to RxJS

Let’s take an example of pipe usage in RxJS.

number$.pipe(
map(n => n * n),
filter(n => n % 2 === 0)
);

We can also write it in a different way:

const { pipe } = rxjs;

const transformNumbers = pipe(
map(x => x * x),
filter(x => x % 2 === 0),
); transformNumbers(number$).subscribe(console.log);

And the result is exactly the same! As you can see, the pipe function in RxJS behaves in exactly the same way that the pipe function that we’ve defined in the first part of the article. It takes a number of functions and composes them by passing the result of a function as an argument to another function. You might say that this is different than the previous example because here we’re invoking map and filter and not simply passing them. Actually, both map and filter will return functions. We’re not composing map and filter themselves but rather the functions returned by invoking them. You can check out how RxJS implements pipe function here.

Pipeline operator

Our function is such a useful concept that it might be added as a separate operator to the JavaScript language! It would mean that the example from the previous article can be written in an even simpler way:

const logElementValue = getElement |> getValue |> console.log;

You can see the details of the proposal here.

Summary

I hope this article helped you understand what pipe function is all about. You should now feel more comfortable using it! The fact that RxJS migrated from the traditional, object-oriented approach of applying operators to the pipeline approach shows how strong the influence of functional programming is nowadays. I think that’s great! Let me know in comments if you prefer pipe function to traditional method chaining.

【转】Deep dive into pipe function in RxJS的更多相关文章

  1. [RxJS] Chain RxJS Operators Together with a Custom `pipe` Function using Array.reduce

    Instead of writing complex operators, it's usually best to write simple, single-purpose operators th ...

  2. X64 Deep Dive

    zhuan http://www.codemachine.com/article_x64deepdive.html X64 Deep Dive This tutorial discusses some ...

  3. 《Docker Deep Dive》Note - Docker 引擎

    <Docker Deep Dive>Note Docker 引擎 1. 概览 graph TB A(Docker client) --- B(daemon) subgraph Docker ...

  4. Deep Dive into Neo4j 3.5 Full Text Search

    In this blog we will go over the Full Text Search capabilities available in the latest major release ...

  5. Deep Dive into Spark SQL’s Catalyst Optimizer(中英双语)

    文章标题 Deep Dive into Spark SQL’s Catalyst Optimizer 作者介绍 Michael Armbrust, Yin Huai, Cheng Liang, Rey ...

  6. 《Docker Deep Dive》Note - 纵观 Docker

    <Docker Deep Dive>Note 由于GFW的隔离,国内拉取镜像会报TLS handshake timeout的错误:需要配置 registry-mirrors 为国内源解决这 ...

  7. 重磅解读:K8s Cluster Autoscaler模块及对应华为云插件Deep Dive

    摘要:本文将解密K8s Cluster Autoscaler模块的架构和代码的Deep Dive,及K8s Cluster Autoscaler 华为云插件. 背景信息 基于业务团队(Cloud BU ...

  8. vue3 deep dive

    vue3 deep dive vue core vnode vue core render / mount / patch refs https://www.vuemastery.com/course ...

  9. A Deep Dive Into Draggable and DragTarget in Flutter

    https://medium.com/flutter-community/a-deep-dive-into-draggable-and-dragtarget-in-flutter-487919f6f1 ...

随机推荐

  1. SLA 99.99%以上!饿了么实时计算平台3年演进历程

    作者介绍 倪增光,饿了么BDI-大数据平台研发高级技术经理,曾先后就职于PPTV.唯品会.15年加入饿了么,组建数据架构team,整体负责离线平台.实时平台.平台工具的开发和运维,先后经历了唯品会.饿 ...

  2. tp5之服务器不显示验证码

    今天在使用tp框架的时候遇到的一个bug,前辈们早已有解决方法,遇到了做个笔记 TP5框架,自带的验证码在本地localhost运行是没问题的,可以正常显示,如图: 然后,把框架拿到服务器是去运行,验 ...

  3. kindeditor——开源的HTML可视化编辑器

    官网:http://kindeditor.net/demo.php 主要操作文档:http://kindeditor.net/docs/option.html

  4. celery无法启动的问题 SyntaxError: invalid syntax

    遇到了celery无法启动的问题,报错:SyntaxError: invalid syntax ,这是因为我使用的python版本为最新3.7.3 ,而async已经作为关键字而存在了 在 celer ...

  5. springboot热部署JRebel插件

    激活参考:https://www.52pojie.cn/thread-906163-1-1.html 最后设置为离线,不然每次启动要重新激活 环境idea是2018.1.1版本 JRebel是最新版2 ...

  6. Linux中DHCP服务器的简单配置(转)

    我安装了两台linux系统,一个作为服务器,一个客户端 两个都有3个网卡, 后两个网卡聚合为zhi一个网卡:Linux 网卡聚合 两台电脑都一样. 那么如何为这个聚合网卡进行DHCP的分配呢? 1.由 ...

  7. OpenDrive格式地图

    https://blog.csdn.net/lewif/article/details/78575840 UE 编辑spline: https://docs.unrealengine.com/en-U ...

  8. c+11 std::condition_variable and mutex

    multiple threads synchronization primitive: 多线程同步语义 多线程的同步语义是多线程编程的核心,线程之间通过同步语义进行通信,实现并发.C++ JAVA 中 ...

  9. handy网络库源码阅读

    简洁易用的C++11网络库,From:https://github.com/yedf/handy 在整理过去的资料过程中,发现过去有关注过这一个网络库,简单看了一下属于轻量级的实现,因此本文将对该库进 ...

  10. mysql5.5免安装版配置教程

    1. 下载免安装版 ,解压缩 2. 配置MYSQL的环境变量 新增系统变量MYSQL_HOME:安装目录 在PATH变量的最后面添加: ;%MYSQL_HOME%\bin(注意前面的:) 3. 打开文 ...