To strategier: offset-baseret (limit/offset) og cursor-baseret. GraphQL har ingen indbygget paginering, men fællesskabets standard er Relay Connection-specifikationen, som formaliserer cursor-paginering.
To strategier: offset-baseret (limit/offset) og cursor-baseret. GraphQL har ingen indbygget paginering, men fællesskabets standard er Relay Connection-specifikationen, som formaliserer cursor-paginering.
items(limit: 10, offset: 20)) er enkel, men fejler på live-data: hvis en række indsættes, mens brugeren bladrer, forskydes elementer, og du ser dubletter eller huller. Den bliver også langsom ved dybe offsets (DB'en scanner stadig de oversprungne rækker).En connection indkapsler listen i edges (hver med en cursor og en node) plus pageInfo:
type Query {
posts(first: Int!, after: String): PostConnection! # first = page size, after = cursor
}
type PostConnection {
edges: [PostEdge!]!
pageInfo: PageInfo!
}
type PostEdge {
cursor: String! # opaque token for THIS node's position
node: Post! # the actual item
}
type PageInfo {
endCursor: String # feed this back as 'after' for the next page
hasNextPage: Boolean! # so the client knows when to stop
}
// resolver: fetch ONE extra row to compute hasNextPage cheaply
const rows = await db.posts.find({ after: args.after, limit: args.first + 1 });
const hasNextPage = rows.length > args.first;
const page = rows.slice(0, args.first);
return {
edges: page.map((p) => ({ node: p, cursor: encodeCursor(p.id) })),
pageInfo: { endCursor: page.at(-1) && encodeCursor(page.at(-1).id), hasNextPage },
};
Cursoren er opaque — normalt en base64 af sorteringsnøglen — så klienter behandler den som et token, ikke et tal.
At vælge offset vs. cursor viser, at du forstår konsistens under samtidige skrivninger og ydeevne ved dybe sider. At kende Relay-connection-formen betyder noget, fordi Apollo/Relay-klienter har indbygget cache-håndtering af den.
Et bibliotek af IT-interviewspørgsmål med detaljerede svar — fra Junior til Senior.
Donér