如何在前端开发时优雅的使用pipe

前言

pipe其实是一种设计思想,经常被用于架构设计,也能体现‘函数式编程’ 思想 — 通过组合一系列的函数来完成一个既定的功能。而在前端开发中,本身强调 组合大于继承,所以掌握这种思想是十分重要的。

实例

pipe大概像如下那样使用

// 假设有个三个方法,分别实现+1, 求与2的乘积,-1 这三个功能
let add = n => n + 3;
let multiple = n => n * 2;
let minus = n => n - 1;

// 假设现在有个pipe方法
const pipe = () => {} 

// 那么我现在可以这样
console.log(pipe()(10)); // 10
console.log(pipe(add,multiple,minus)(10)); //25 
console.log(pipe(add,minus, multiple)(10)); // 24


可以看到,通过组合这三个方法,我们可以得到实现各种组合功能的函数。有这么几个优点

  1. 符合设计模式的单一职责原则
    – 因为我们要组合不同的函数,所以会尽量拆分函数功能,一个函数只完成一个最原子性的功能。便于维护
  2. 符合设计模式的开闭原则
    – 因为一般原子性的函数不太会修改,我们只需要修改下组合的逻辑即可,或者去构造新的组合来实现新的功能。
  3. 方便单元测试
    – 这个很好理解,一个原子性的函数可以理解为一个便于测试的单元

下面我们简单看下pipe可以怎么实现。

实现
const pipe = (...args) => x => args.reduce((acc,cur) => cur(acc),x); 

其实根据pipe的思想,在前端中很快就能想到利用reduce这个高阶函数来实现。

其他

其实还有一种compose的思想,和pipe十分类似,但是针对函数的组合是从后往前的。实现起来也非常简单

const pipe = (...args) => x => args.reduceRight((acc,cur) => cur(acc),x); 
扩展

上面的例子是比较简单的,但是很好地解释了pipe和compose的思想,但是实际开发中,遇到的情况可能要复杂一些,比如,一个函数的逻辑会涉及到异步,这个时候该怎么写呢?这里我们采用promise的写法

// 本质上就是串联promise
const pipe = (...args) => {
  return (x) => {
    return args.reduce((acc, cur) => {
      if (!(acc instanceof Promise)) {
        acc = Promise.resolve(acc);
      }
      const ret = acc.then(cur);
      return ret;
    }, x);
  };
};

const requestProduct = (id) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(`product-tag-${id}`);
    }, 1000);
  });
};

const requestProductSku = (tag) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(`sku-${tag}`);
    }, 1000);
  });
};

// 这里我们要求接受一个参数,并且返回一个promise
const asyncGetProductTag = (id) => {
  return requestProduct(id);
};

const asyncGetProductSku = (tag) => {
  return requestProductSku(tag);
};

const getProductThenGetSKu = pipe(asyncGetProductTag, asyncGetProductSku);
getProductThenGetSKu(10).then((res) => console.log(res));

上述代码我们先根据商品ID去获取到商品的tag,再根据tag去获取商品的sku属性。此时就是一个可以处理异步的情况,注意的是可能每一个函数不一定是异步的,所以我们在pipe函数中处理了这种情况,手动转变为promise。有兴趣的同学也可以试试看compose的异步版本

最后

上面的用法还可以再扩展,比如在管道传递的过程中,到某个节点满足一个要求后可以直接退出,这里就可以reject一个值,然后在catch中去处理。总之这种编程技艺十分重要,尤其是在前端开发的场景中,如果有不同见解欢迎讨论。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值