трейс и первая оптимизация
This commit is contained in:
@@ -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;
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user