FP-TS:映射响应



我正在使用fp-ts库,我不知道如何实现以下场景:

  1. 假设我有一个请求方法为getBooks(shelf,page(的服务,响应如下(请求被分页(:
{ 
totalItems: 100,  
perPage: 25,  
books:[{...}, ...],  
....
}
  1. 所以我想发送一个初始请求,然后计算页数:
const nrOfPages = Math.ceil(totalItems / perPage);
  1. 然后循环获取其余书籍,因为第一个请求只会向我提供前25个书籍项目

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

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

您可以使用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。