【问题标题】:FP-TS: mapping responsesFP-TS:映射响应
【发布时间】:2022-09-25 13:56:36
【问题描述】:

我正在使用FP-TS库,我无法弄清楚如何实现以下场景:

  1. 假设我有一个使用请求方法的服务getBooks(书架,页面)并且响应看起来像这样(请求是分页的):
    { 
        totalItems: 100,  
        perPage: 25,  
        books:[{...}, ...],  
        ....
    }
    
    1. 所以我想发送一个初始请求,然后计算页数:
    const nrOfPages = Math.ceil(totalItems / perPage);
    
    1. 然后循环获取其余书籍,因为第一个请求只会提供前 25 本书。

    现在的斗争是,最后我想把所有的书都收集在一个物体里。基本上,我想等待结果并将它们放在一起。请求应该是顺序的并使用 fp-ts 库也很重要。

    const allBooks [{...},{...},{...}, ...];
    

    标签: typescript functional-programming fp-ts


    【解决方案1】:

    您可以使用Task 模块中的traverseSeqArray 将一组页码映射到任务中以获取每个页面,并且每个任务将按顺序执行。然后,您可以使用concatAll(来自Monoid)来连接书籍数组。

    declare const traverseSeqArray: <A, B>(f: (a: A) => Task<B>) => (as: readonly A[]) => Task<readonly B[]>
    declare const concatAll: <A>(M: Monoid<A>) => (as: readonly A[]) => A
    
    import * as M from 'fp-ts/lib/Monoid';
    import * as RA from 'fp-ts/lib/ReadonlyArray';
    import * as T from 'fp-ts/lib/Task';
    import {flow, pipe} from 'fp-ts/lib/function';
    
    declare const getBooks: (
        shelf: Shelf,
        page: number
    ) => T.Task<{totalItems: number; perPage: number; books: readonly Book[]}>;
    
    const getAllBooks = (shelf: Shelf): T.Task<readonly Book[]> =>
        pipe(
            // Fetch the first page (assuming pages are zero-indexed)
            getBooks(shelf, 0),
            T.chain(({totalItems, perPage, books: firstPageBooks}) => {
                const nrOfPages = Math.ceil(totalItems / perPage);
                // e.g. [1, 2, 3] for 100 books and 25 per page
                const pagesToFetch = Array.from(
                    {length: nrOfPages - 1},
                    (_, i) => i + 1
                );
                return pipe(
                    pagesToFetch,
                    // With each page...
                    T.traverseSeqArray(page =>
                        // ...fetch the books at the page
                        pipe(
                            getBooks(shelf, page),
                            T.map(({books}) => books)
                        )
                    ),
                    // Now we have a Task<Book[][]> that we want to turn into
                    // a Task<Book[]> including the books from the first page
                    T.map(
                        flow(
                            // Prepend the first pages’ books
                            RA.prepend(firstPageBooks),
                            // Concatenate the Book[][] into a Book[]
                            M.concatAll(RA.getMonoid())
                        )
                    )
                );
            })
        );
    

    此示例假定getBooks 没有失败,但可以通过将Task 切换为TaskEither 轻松修改tihs。

    【讨论】:

      猜你喜欢
      • 2021-05-10
      • 1970-01-01
      • 2019-09-24
      • 2018-03-21
      • 2021-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-01
      相关资源
      最近更新 更多