JS 函式式概念: 管道 和 組合

前端小智發表於2023-01-18
微信搜尋 【大遷世界】, 我會第一時間和你分享前端行業趨勢,學習途徑等等。
本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

函式管道和組合是函數語言程式設計中的概念,當然也可以在JavaScript中實現--因為它是一種多正規化的程式語言,讓我們快速深入瞭解這個概念。

這個概念就是按照一定的順序執行多個函式,並將一個函式的結果傳遞給下一個函式。

你可以像這樣做得很難看:

function1(function2(function3(initialArg)))

或者使用函式組合:

compose(function3, function2, function1)(initialArg);

或功能管道:

pipe(function1, function2, function3)(initialArg);

簡而言之,組合和管道幾乎是一樣的,唯一的區別是執行順序;如果函式從左到右執行,就是管道,另一方面,如果函式從右到左執行,就叫組合。

一個更準確的定義是。"在函數語言程式設計中,compose是將較小的單元(我們的函式)組合成更復雜的東西(你猜對了,是另一個函式)的機制"。

下面是一個管道函式的例子。

const pipe = (...functions) => (value) => {
    return functions.reduce((currentValue, currentFunction) => {
      return currentFunction(currentValue);
    }, value);
  };

讓我們來補充一些這方面的見解。

基礎知識

  • 我們需要收集N多的函式
  • 同時選擇一個引數
  • 以鏈式方式執行它們,將收到的引數傳遞給將被執行的第一個函式
  • 呼叫下一個函式,加入第一個函式的結果作為引數。
  • 繼續對陣列中的每個函式做同樣的操作。
/* destructuring to unpack our array of functions into functions */
const pipe = (...functions) => 
  /* value is the received argument */
  (value) => {
    /* reduce helps by doing the iteration over all functions stacking the result */
    return functions.reduce((currentValue, currentFunction) => {
      /* we return the current function, sending the current value to it */
      return currentFunction(currentValue);
    }, value);
  };

我們已經知道,箭頭函式如果只返回一條語句,就不需要括號,也不需要返回標籤,所以我們可以透過這樣寫來減少鍵盤的點選次數。

const pipe = (...functions) => (input) => functions.reduce((chain, func) => func(chain), input);

如何使用

const pipe = (...fns) => (input) => fns.reduce((chain, func) => func(chain), input);

const sum = (...args) => args.flat(1).reduce((x, y) => x + y);

const square = (val) => val*val; 

pipe(sum, square)([3, 5]); // 64

記住,第一個函式是左邊的那個(Pipe),所以3+5=8,8的平方是64。我們的測試很順利,一切似乎都很正常,但如果要用鏈式 async 函式呢?

非同步函式上的管道

我在這方面的一個用例是有一箇中介軟體來處理客戶端和閘道器之間的請求,過程總是相同的(做請求,錯誤處理,挑選響應中的資料,處理響應以烹製一些資料,等等等等),所以讓它看起來像一個魅力。

export default async function handler(req, res) {
  switch (req.method) {
    case 'GET':
      return pipeAsync(provide, parseData, answer)(req.headers);
     /* 
       ... 
     */ 

讓我們看看如何在Javascript和Typescript中處理非同步函式管道。

JS版

export const pipeAsync =
  (...fns) =>
  (input) =>
    fns.reduce((chain, func) => chain.then(func), Promise.resolve(input));

新增了JSDoc型別,使其更容易理解(我猜)。

/**
 * Applies Function piping to an array of async Functions.
 * @param  {Promise<Function>[]} fns
 * @returns {Function}
 */
export const pipeAsync =
  (...fns) =>
  (/** @type {any} */ input) =>
    fns.reduce((/** @type {Promise<Function>} */ chain, /** @type {Function | Promise<Function> | any} */ func) => chain.then(func), Promise.resolve(input));

TS版

export const pipeAsync: any =
  (...fns: Promise<Function>[]) =>
  (input: any) =>
    fns.reduce((chain: Promise<Function>, func: Function | Promise<Function> | any) => chain.then(func), Promise.resolve(input));

這樣一來,它對非同步和非非同步函式都有效,所以它比上面的例子更勝一籌。

你可能想知道函式的組成是什麼,所以讓我們來看看。

函式組合

如果你喜歡從右到左呼叫這些函式,你只需要將reduce改為redureRight,就可以了。讓我們看看用函式組成的非同步方式。

export const composeAsync =
  (...fns) =>
  (input) =>
    fns.reduceRight((chain, func) => chain.then(func), Promise.resolve(input));

回到上面的例子,讓我們複製同樣的內容,但要有構圖。

如何使用

const compose = (...fns) => (input) => fns.reduceRight((chain, func) => func(chain), input);

const sum = (...args) => args.flat(1).reduce((x, y) => x + y);

const square = (val) => val*val; 

compose(square, sum)([3, 5]); // 64

請注意,我們顛倒了函式的順序,以保持與帖子頂部的例子一致。

現在,sum(位於最右邊的位置)將被首先呼叫,因此3+5=8,然後8的平方是64。

原文:https://dev.to/joelbonetr/js-...

交流

有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

交流

有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

相關文章