Postun altında 5000 şərh yığılıb. Onları bir cavabda göndərmək olmaz: server, şəbəkə və brauzer boğular. Kitabla necə rəftar edirlərsə, eləcə: səhifə-səhifə oxuyurlar, əlfəcin isə harada dayandığınızı göstərir. Bu, səhifələmədir, əlfəcinin adı isə cursor-dur. İkinci məsələ də var: siz oxuyarkən postun altında yeni şərhlər görünür. Serverdən hər beş saniyədən bir soruşmaq (polling) yorucudur, zəngi eşitmək daha yaxşıdır. Bu, subscription-dur (abunə). Bu dərsdə «Daha çox yüklə» düyməsi olan və yeni şərhləri real vaxtda göstərən şərh lenti düzəldəcəksiniz.
Offset yoxsa cursor
Ən sadə üsul offset-dir: «10-nu keç, növbəti 10-u ver» (skip və take, Prisma mövzusundakı kimi). O, dərhal 50-ci səhifəyə keçməyə imkan verir, amma iki çatışmazlığı var. Dərin səhifələr yavaşdır: verilənlər bazası keçilən sətirləri yenə də gəzir. Oxuyarkən nəsə əlavə olunsa, səhifələr «sürüşür»: elementlər təkrarlanır və ya itir.
Cursor isə başqa cür deyir: «bu əlfəcindən sonrakı 10 qeydi ver». Sorğu indeksdən keçir, dərinlikdən asılı deyil və yeni qeydlərdən pozulmur. Əvəzində 50-ci səhifəyə dərhal keçmək olmur: yalnız «irəli».
Relay connection: edges, node, cursor, pageInfo
GraphQL-də cursor ilə səhifələmənin ümumi razılaşması var — Relay spesifikasiyasındakı connection. Sahə siyahı yox, üç hissəli obyekt qaytarır:
edges— «zərflər» siyahısı; hər birindənode(şərhin özü) vəcursor(məhz ona qoyulmuş əlfəcin) var. Zərf obyekt haqqında yox, əlaqə haqqında məlumat saxlamaq üçündür.pageInfo— naviqasiya:hasNextPage(«daha var?») vəendCursor(«son elementin əlfəcini»).totalCount— spesifikasiyaya tez-tez edilən əlavə: cəmi neçə element olduğu (bizim sxemdə sahə məcburidir).
Spesifikasiyada pageInfo-da geriyə hərəkət üçün hasPreviousPage və startCursor da var; bizə iki sahə bəs edir. Əvvəlki dərslərdəki Post.comments sahəsi indi connection qaytarır (tədris layihəsində kənar müştəri yoxdur, canlı API-də sxemi belə pozmaq olmaz):
type PageInfo {
hasNextPage: Boolean!
endCursor: String
}
type CommentEdge {
cursor: String!
node: Comment!
}
type CommentConnection {
edges: [CommentEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type Post {
# ...the other fields as before
comments(first: Int = 10, after: String): CommentConnection!
}Server: Prisma-da cursor
Müştəri üçün cursor şəffaf olmayan sətirdir: onu təhlil etməməli və məzmununu təxmin etməməlidir. Biz şərhin id-sini base64url ilə kodlaşdırırıq. Üç qayda: sıralama unikal və dəyişməyən sahəyə (id) söykənir, səhifənin ölçüsü məhduddur, hasNextPage-i bilmək üçün isə bir qeyd artıq oxuyuruq. Prisma sorğusu Prisma mövzusundakı ilə eynidir: cursor, skip: 1, take.
// src/resolvers/post.ts
const encodeCursor = (id: number) =>
Buffer.from(String(id)).toString('base64url');
function decodeCursor(cursor: string): number {
const id = Number(Buffer.from(cursor, 'base64url').toString());
if (!Number.isInteger(id)) {
throw new GraphQLError('Invalid cursor', {
extensions: { code: 'BAD_USER_INPUT' },
});
}
return id;
}