Это в моем UserScript. Подсветка синтаксиса для typescript не работает, а js ведёт себя странно. Нужно указывать javascript. При этом ts и typescript работают на StackOverflow.
interface IPost {
id: number
username: string
post_number: number
cooked: string
}
interface ITopicResponse {
actions_summary: {}[]
archetype: string
fancy_title: string
title: string
post_stream: {
posts: IPost[]
stream: number[]
}
posts_count: number
reply_count: number
}
export async function jsonFetch<T>(url: string): Promise<T | null> {
const r = await fetch(url)
if (r.ok) {
const json = await r.json()
if (!json.errors) {
return json
}
}
logger('error', r)
return null
}
export async function fetchAll(urlBase: string) {
const r0 = await jsonFetch<ITopicResponse>(urlBase + '.json?print=true')
if (!r0) return []
const posts: IPost[] = r0.post_stream.posts
let page = 2
while (posts.length < r0.posts_count) {
const r = await jsonFetch<ITopicResponse>(
urlBase + '.json?print=true&page=' + page++
)
if (!r || !r.post_stream.posts.length) {
break
}
posts.push(...r.post_stream.posts)
await new Promise((resolve) => setTimeout(resolve, 1000))
}
return posts
}
fetchAll('https://community.wanikani.com/t/16404').then(console.log)
В скрипте на ts-node с использованием Axios:
(node:1102374) UnhandledPromiseRejectionWarning: Error: Request failed with status code 422
Если подождать достаточно долго, например 10 минут, ошибка возникнет на странице 2; но если повторить попытку прямо сейчас, ни один URL не загрузится.
А без print всё работает нормально.
На самом деле мне удалось заставить это работать, исключив print=true.
export async function fetchAll(urlBase: string) {
const r0 = await jsonFetch<ITopicResponse>(urlBase + '.json');
if (!r0) return [];
const stream = r0.post_stream.stream || [];
const chunks: number[][] = [];
while (stream.length) {
chunks.push(stream.splice(0, 300));
}
const posts: IPost[] = [];
let isContinue = true;
while (chunks.length && isContinue) {
const rs = await Promise.all(
chunks
.splice(0, 10)
.map((ids) =>
jsonFetch<ITopicPostResponse>(
urlBase +
'/posts.json?' +
ids.map((id) => `post_ids[]=${id}`).join('&'),
),
),
).then((rs) =>
rs.map((r) => {
if (!r) {
isContinue = false;
return [];
}
return r.post_stream.posts;
}),
);
rs.map((r) => {
posts.push(...r);
});
if (chunks.length) {
await new Promise((r) => setTimeout(r, 1000));
}
}
posts.push(...r0.post_stream.posts);
if (!isContinue) {
logger(
'error',
`Total posts: ${r0.posts_count} != real count: ${posts.length}, due to Rate Limit?`,
);
}
return posts;
}