[Perf] API: Batch updates into single postMessage

This commit is contained in:
Alexander Zinchuk 2023-07-23 10:07:41 +02:00
parent 06098dd821
commit 19e02501af
3 changed files with 37 additions and 12 deletions

View File

@ -1,7 +1,7 @@
import type { Api } from '../../../lib/gramjs';
import type { ApiInitialArgs, ApiOnProgress, OnApiUpdate } from '../../types';
import type { Methods, MethodArgs, MethodResponse } from '../methods/types';
import type { WorkerMessageEvent, OriginRequest, ThenArg } from './types';
import type { MethodArgs, MethodResponse, Methods } from '../methods/types';
import type { OriginRequest, ThenArg, WorkerMessageEvent } from './types';
import type { LocalDb } from '../localDb';
import type { TypedBroadcastChannel } from '../../../util/multitab';
@ -254,8 +254,22 @@ export function cancelApiProgressMaster(messageId: string) {
function subscribeToWorker(onUpdate: OnApiUpdate) {
worker?.addEventListener('message', ({ data }: WorkerMessageEvent) => {
if (!data) return;
if (data.type === 'update') {
onUpdate(data.update);
if (data.type === 'updates') {
// eslint-disable-next-line @typescript-eslint/naming-convention
let DEBUG_startAt: number | undefined;
if (DEBUG) {
DEBUG_startAt = performance.now();
}
data.updates.forEach(onUpdate);
if (DEBUG) {
const duration = performance.now() - DEBUG_startAt!;
if (duration > 5) {
// eslint-disable-next-line no-console
console.warn(`[API] Slow updates processing: ${data.updates.length} updates in ${duration} ms`);
}
}
} else if (data.type === 'methodResponse') {
handleMethodResponse(data);
} else if (data.type === 'methodCallback') {

View File

@ -6,8 +6,8 @@ import type { DebugLevel } from '../../../util/debugConsole';
export type ThenArg<T> = T extends Promise<infer U> ? U : T;
export type WorkerMessageData = {
type: 'update';
update: ApiUpdate;
type: 'updates';
updates: ApiUpdate[];
} | {
type: 'methodResponse';
messageId: string;

View File

@ -4,10 +4,11 @@ import type { ApiOnProgress, ApiUpdate } from '../../types';
import type { OriginMessageEvent, WorkerMessageData } from './types';
import { DEBUG } from '../../../config';
import { initApi, callApi, cancelApiProgress } from '../provider';
import { callApi, cancelApiProgress, initApi } from '../provider';
import { log } from '../helpers';
import type { DebugLevel } from '../../../util/debugConsole';
import { DEBUG_LEVELS } from '../../../util/debugConsole';
import { throttleWithTickEnd } from '../../../util/schedulers';
declare const self: WorkerGlobalScope;
@ -154,15 +155,25 @@ function handleErrors() {
});
}
function onUpdate(update: ApiUpdate) {
sendToOrigin({
type: 'update',
update,
});
let pendingUpdates: ApiUpdate[] = [];
const sendUpdatesOnTickEnd = throttleWithTickEnd(() => {
const currentUpdates = pendingUpdates;
pendingUpdates = [];
sendToOrigin({
type: 'updates',
updates: currentUpdates,
});
});
function onUpdate(update: ApiUpdate) {
if (DEBUG && update['@type'] !== 'updateUserStatus' && update['@type'] !== 'updateServerTimeOffset') {
log('UPDATE', update['@type'], update);
}
pendingUpdates.push(update);
sendUpdatesOnTickEnd();
}
export function sendToOrigin(data: WorkerMessageData, arrayBuffer?: ArrayBuffer) {