трейс и первая оптимизация

This commit is contained in:
gorbenko.pavel
2026-08-20 16:40:05 +05:00
parent e90a8ea3cc
commit c6c549eae9
9 changed files with 690 additions and 155 deletions
@@ -0,0 +1,65 @@
import { WebPartContext } from '@microsoft/sp-webpart-base';
import { spForSite } from '../pnp/pnpjs';
import '@pnp/sp/webs';
import '@pnp/sp/site-users/web';
/**
* Числовой Id пользователя НА КОНКРЕТНОМ САЙТЕ — с кешом на сессию.
*
* Зачем: почти все фильтры SharePoint REST по Person-полям строятся по числовому
* Id (`AuthorId eq N`, `TansuSiteApproverId eq N`) — фильтр по EMail у Person-поля
* ненадёжен. Id свой на каждом сайте, поэтому его приходится резолвить, но
* в пределах сессии он не меняется.
*
* Раньше резолв стоял ВНУТРИ функций, которые вызываются в цикле по типам заявок
* (getOwnRowsForType / getRecentlyChangedOwnRowsForType): при восьми типах это
* восемь одинаковых GET /_api/web/currentuser подряд, и каждый — лишний
* round-trip ПЕРЕД основным запросом. ensureUser в очереди согласования — то же
* самое, только POST.
*
* Ошибку НЕ кешируем: упавший на холодном старте запрос должен повториться,
* а не залипнуть до конца сессии (тот же принцип, что у requestTypesPromise
* в approvalRoute.service.ts).
*/
const byKey = new Map<string, Promise<number>>();
function remember(key: string, load: () => Promise<number>): Promise<number> {
const pending = byKey.get(key);
if (pending) return pending;
const promise = load().catch((e) => {
byKey.delete(key);
throw e;
});
byKey.set(key, promise);
return promise;
}
/** Полный сброс — на случай смены личности (отладочная подмена) или реинициализации. */
export function resetSiteUserCache(): void {
byKey.clear();
}
/** Id ТЕКУЩЕГО (реального) пользователя на сайте. */
export async function currentUserIdFor(context: WebPartContext, siteUrl: string): Promise<number> {
return remember(`current|${siteUrl.toLowerCase()}`, async () => {
const me = await spForSite(siteUrl, context).web.currentUser.select('Id')();
return me.Id as number;
});
}
/**
* Id пользователя по claims-логину. ensureUser — это POST (он при необходимости
* заводит пользователя в коллекции сайта), поэтому повторять его особенно жаль.
*/
export async function ensureUserIdFor(
context: WebPartContext,
siteUrl: string,
claimsLogin: string
): Promise<number> {
return remember(`ensure|${siteUrl.toLowerCase()}|${claimsLogin.toLowerCase()}`, async () => {
const user = await spForSite(siteUrl, context).web.ensureUser(claimsLogin);
return user.Id;
});
}