оптимизация
This commit is contained in:
@@ -16,6 +16,7 @@ import { IMyRequest } from './models/IMyRequest';
|
|||||||
import { DataTable, IDataTableColumn } from '@tnsu/ui-kit';
|
import { DataTable, IDataTableColumn } from '@tnsu/ui-kit';
|
||||||
import { REQUEST_STATUS, REQUEST_STATUS_CHOICES, IRequestType, StatusBadge } from '../../shared/approval';
|
import { REQUEST_STATUS, REQUEST_STATUS_CHOICES, IRequestType, StatusBadge } from '../../shared/approval';
|
||||||
import { onRequestsChanged } from '../../shared/requestEvents';
|
import { onRequestsChanged } from '../../shared/requestEvents';
|
||||||
|
import { traced } from './perfTrace';
|
||||||
import { useRoutedQuery } from '../../shared/usePersistedQuery';
|
import { useRoutedQuery } from '../../shared/usePersistedQuery';
|
||||||
import { IPage, pageKey, pageSignature, readPage, writePage } from './pageCache';
|
import { IPage, pageKey, pageSignature, readPage, writePage } from './pageCache';
|
||||||
import { Pager } from './Pager';
|
import { Pager } from './Pager';
|
||||||
@@ -394,7 +395,7 @@ export const RequestsTableView: React.FC<IRequestsTableViewProps> = ({
|
|||||||
|
|
||||||
const load = async (forceRender = false): Promise<void> => {
|
const load = async (forceRender = false): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
const fresh = await fetchPage();
|
const fresh = await traced(`ИТОГО таблица:${view}#${page}`, fetchPage);
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
|
|
||||||
// Перерисовываем, только если данные реально изменились — иначе при
|
// Перерисовываем, только если данные реально изменились — иначе при
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { getLinkedTypes, hydratePendingAuthors, searchMyRequests } from './myReq
|
|||||||
import { IMyRequest } from './models/IMyRequest';
|
import { IMyRequest } from './models/IMyRequest';
|
||||||
import { IRequestType, StatusBadge } from '../../shared/approval';
|
import { IRequestType, StatusBadge } from '../../shared/approval';
|
||||||
import { onRequestsChanged } from '../../shared/requestEvents';
|
import { onRequestsChanged } from '../../shared/requestEvents';
|
||||||
|
import { traced } from './perfTrace';
|
||||||
import { useRoutedQuery } from '../../shared/usePersistedQuery';
|
import { useRoutedQuery } from '../../shared/usePersistedQuery';
|
||||||
import { pageKey, pageSignature, readPage, writePage } from './pageCache';
|
import { pageKey, pageSignature, readPage, writePage } from './pageCache';
|
||||||
import { Pager } from './Pager';
|
import { Pager } from './Pager';
|
||||||
@@ -184,7 +185,7 @@ export const SearchView: React.FC<ISearchViewProps> = ({
|
|||||||
|
|
||||||
const load = async (forceRender = false): Promise<void> => {
|
const load = async (forceRender = false): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
const fresh = await searchMyRequests(context, types, debouncedQuery);
|
const fresh = await traced('ИТОГО поиск', () => searchMyRequests(context, types, debouncedQuery));
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
applyKnownAuthors(fresh.rows, authors.current);
|
applyKnownAuthors(fresh.rows, authors.current);
|
||||||
const prev = readPage(cacheKey);
|
const prev = readPage(cacheKey);
|
||||||
|
|||||||
@@ -232,6 +232,10 @@ export interface INavCounts {
|
|||||||
// своим запросом — но параллельно, и ровно тем же вызовом, что наполняет саму
|
// своим запросом — но параллельно, и ровно тем же вызовом, что наполняет саму
|
||||||
// вкладку: иначе счётчик и список могли бы разойтись.
|
// вкладку: иначе счётчик и список могли бы разойтись.
|
||||||
export async function getNavCounts(context: WebPartContext): Promise<INavCounts> {
|
export async function getNavCounts(context: WebPartContext): Promise<INavCounts> {
|
||||||
|
return traced('ИТОГО getNavCounts', () => getNavCountsInner(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getNavCountsInner(context: WebPartContext): Promise<INavCounts> {
|
||||||
const types = await getLinkedTypes(context);
|
const types = await getLinkedTypes(context);
|
||||||
|
|
||||||
const [turn, rework] = await Promise.all([
|
const [turn, rework] = await Promise.all([
|
||||||
@@ -352,8 +356,15 @@ async function indexApprovalsForPartition(
|
|||||||
const sp = spForSite(target.siteUrl, context);
|
const sp = spForSite(target.siteUrl, context);
|
||||||
const list = sp.web.getList(target.listId);
|
const list = sp.web.getList(target.listId);
|
||||||
|
|
||||||
const dataListInfo = await traced(`dataListTitle:${type.name}#${target.listId}`, () => list.select('Title')());
|
// target.title — из bulk-ответа /api/request-types/lists, уже загруженного
|
||||||
const dataTitle = (dataListInfo.Title as string) || '';
|
// при старте страницы (см. IListTarget.title): 11 партиций — это 11 лишних
|
||||||
|
// REST-запросов только за тем, что уже пришло бесплатно одним запросом.
|
||||||
|
// REST — только если реестр партиций был недоступен (see listTargetsForType),
|
||||||
|
// тогда Title взять больше неоткуда.
|
||||||
|
const dataTitle =
|
||||||
|
target.title ??
|
||||||
|
((await traced(`dataListTitle:${type.name}#${target.listId}`, () => list.select('Title')())).Title as string) ??
|
||||||
|
'';
|
||||||
if (!DATA_LIST_SUFFIX.test(dataTitle)) {
|
if (!DATA_LIST_SUFFIX.test(dataTitle)) {
|
||||||
debug.approvalSkippedReason = `«${dataTitle}» не оканчивается на «— данные» — список согласования не ищем`;
|
debug.approvalSkippedReason = `«${dataTitle}» не оканчивается на «— данные» — список согласования не ищем`;
|
||||||
return debug;
|
return debug;
|
||||||
@@ -707,6 +718,14 @@ export interface IListTarget {
|
|||||||
siteUrl: string;
|
siteUrl: string;
|
||||||
/** Абсолютный префикс пути элементов этого списка, со слешем на конце. */
|
/** Абсолютный префикс пути элементов этого списка, со слешем на конце. */
|
||||||
prefix: string;
|
prefix: string;
|
||||||
|
/**
|
||||||
|
* Title списка данных на момент регистрации партиции (см. IListPartition.title) —
|
||||||
|
* уже пришёл бесплатно вместе с bulk-ответом /api/request-types/lists при
|
||||||
|
* старте страницы. Заполнен только когда партиция известна реестру; для
|
||||||
|
* фолбэка по RequestType.listId (реестр недоступен) — undefined, тогда
|
||||||
|
* indexApprovalsForPartition сам дочитает Title через REST.
|
||||||
|
*/
|
||||||
|
title?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -731,7 +750,8 @@ export function listTargetsForType(type: IRequestType): IListTarget[] {
|
|||||||
return partitions.map((p) => ({
|
return partitions.map((p) => ({
|
||||||
listId: p.listId,
|
listId: p.listId,
|
||||||
siteUrl: p.siteUrl,
|
siteUrl: p.siteUrl,
|
||||||
prefix: `${siteOrigin(p.siteUrl).replace(/\/+$/, '')}${p.listId.replace(/\/+$/, '')}/`
|
prefix: `${siteOrigin(p.siteUrl).replace(/\/+$/, '')}${p.listId.replace(/\/+$/, '')}/`,
|
||||||
|
title: p.title
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,20 +3,15 @@
|
|||||||
* (индекс согласований, свои заявки по типу, конкретная партиция, Search),
|
* (индекс согласований, свои заявки по типу, конкретная партиция, Search),
|
||||||
* а не просто «страница долго грузится».
|
* а не просто «страница долго грузится».
|
||||||
*
|
*
|
||||||
* Включение/выключение БЕЗ пересборки — из консоли браузера:
|
* ВРЕМЕННО: пишет всегда, без флага-переключателя — этот модуль и все traced()
|
||||||
* window.rpPerfTrace = true // писать тайминги
|
* вокруг снимаются целиком, как только разбор текущей проблемы с
|
||||||
* window.rpPerfTrace = false // выключить (по умолчанию)
|
* производительностью закончится (см. myRequests.service.ts, RequestsTableView.tsx,
|
||||||
|
* SearchView.tsx).
|
||||||
*/
|
*/
|
||||||
function enabled(): boolean {
|
|
||||||
return !!(window as unknown as { rpPerfTrace?: boolean }).rpPerfTrace;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PREFIX = '[Перф]';
|
const PREFIX = '[Перф]';
|
||||||
|
|
||||||
/** Оборачивает async-шаг замером времени. Без включённой трассировки — просто вызывает fn(). */
|
/** Оборачивает async-шаг замером времени. */
|
||||||
export async function traced<T>(label: string, fn: () => Promise<T>): Promise<T> {
|
export async function traced<T>(label: string, fn: () => Promise<T>): Promise<T> {
|
||||||
if (!enabled()) return fn();
|
|
||||||
|
|
||||||
const start = performance.now();
|
const start = performance.now();
|
||||||
try {
|
try {
|
||||||
return await fn();
|
return await fn();
|
||||||
|
|||||||
Reference in New Issue
Block a user