[Dev] TeactN: Assert when setting global asynchronously
This commit is contained in:
parent
fbe03b556b
commit
a7e2695f2e
@ -65,7 +65,7 @@ import {
|
||||
selectSendAs,
|
||||
selectSponsoredMessage,
|
||||
} from '../../selectors';
|
||||
import { debounce, rafPromise } from '../../../util/schedulers';
|
||||
import { debounce, onTickEnd, rafPromise } from '../../../util/schedulers';
|
||||
import { isServiceNotificationMessage } from '../../helpers';
|
||||
|
||||
const uploadProgressCallbacks = new Map<number, ApiOnProgress>();
|
||||
@ -113,7 +113,9 @@ addActionHandler('loadViewportMessages', (global, actions, payload) => {
|
||||
}
|
||||
|
||||
if (!areAllLocal) {
|
||||
void loadViewportMessages(chat, threadId, offsetId, LoadMoreDirection.Around, isOutlying, isBudgetPreload);
|
||||
onTickEnd(() => {
|
||||
void loadViewportMessages(chat, threadId, offsetId, LoadMoreDirection.Around, isOutlying, isBudgetPreload);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const offsetId = direction === LoadMoreDirection.Backwards ? viewportIds[0] : viewportIds[viewportIds.length - 1];
|
||||
@ -127,7 +129,9 @@ addActionHandler('loadViewportMessages', (global, actions, payload) => {
|
||||
global = safeReplaceViewportIds(global, chatId, threadId, newViewportIds);
|
||||
}
|
||||
|
||||
void loadWithBudget(actions, areAllLocal, isOutlying, isBudgetPreload, chat, threadId, direction, offsetId);
|
||||
onTickEnd(() => {
|
||||
void loadWithBudget(actions, areAllLocal, isOutlying, isBudgetPreload, chat, threadId, direction, offsetId);
|
||||
});
|
||||
|
||||
if (isBudgetPreload) {
|
||||
return undefined;
|
||||
@ -149,8 +153,6 @@ async function loadWithBudget(
|
||||
}
|
||||
|
||||
if (!isBudgetPreload) {
|
||||
// Let reducer return and update global
|
||||
await Promise.resolve();
|
||||
actions.loadViewportMessages({
|
||||
chatId: chat.id, threadId, direction, isBudgetPreload: true,
|
||||
});
|
||||
|
||||
@ -47,6 +47,7 @@ import {
|
||||
import {
|
||||
getMessageContent, isUserId, isMessageLocal, getMessageText, checkIfReactionAdded,
|
||||
} from '../../helpers';
|
||||
import { onTickEnd } from '../../../util/schedulers';
|
||||
|
||||
const ANIMATION_DELAY = 350;
|
||||
|
||||
@ -497,10 +498,12 @@ addActionHandler('apiUpdate', (global, actions, update) => {
|
||||
if (shouldNotify) {
|
||||
const newMessage = selectChatMessage(global, chatId, id);
|
||||
if (!chat || !newMessage) return;
|
||||
notifyAboutMessage({
|
||||
chat,
|
||||
message: newMessage,
|
||||
isReaction: true,
|
||||
onTickEnd(() => {
|
||||
notifyAboutMessage({
|
||||
chat,
|
||||
message: newMessage,
|
||||
isReaction: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -548,13 +551,15 @@ function updateThreadUnread(global: GlobalState, actions: GlobalActions, message
|
||||
if (originMessage) {
|
||||
global = updateThreadUnreadFromForwardedMessage(global, originMessage, chatId, message.id, isDeleting);
|
||||
} else {
|
||||
actions.loadMessage({
|
||||
chatId,
|
||||
messageId: message.replyToMessageId,
|
||||
threadUpdate: {
|
||||
isDeleting,
|
||||
lastMessageId: message.id,
|
||||
},
|
||||
onTickEnd(() => {
|
||||
actions.loadMessage({
|
||||
chatId,
|
||||
messageId: message.replyToMessageId,
|
||||
threadUpdate: {
|
||||
isDeleting,
|
||||
lastMessageId: message.id,
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,10 @@ import { cloneDeep } from '../util/iteratees';
|
||||
|
||||
initCache();
|
||||
|
||||
addActionHandler('init', () => {
|
||||
addActionHandler('init', (global) => {
|
||||
const initial = cloneDeep(INITIAL_STATE);
|
||||
return loadCache(initial) || initial;
|
||||
return {
|
||||
...global,
|
||||
...(loadCache(initial) || initial),
|
||||
};
|
||||
});
|
||||
|
||||
@ -13,7 +13,9 @@ import { isHeavyAnimating } from '../../hooks/useHeavyAnimationCheck';
|
||||
|
||||
export default React;
|
||||
|
||||
type GlobalState = AnyLiteral;
|
||||
type GlobalState =
|
||||
AnyLiteral
|
||||
& { DEBUG_id: number };
|
||||
type ActionNames = string;
|
||||
type ActionPayload = any;
|
||||
|
||||
@ -35,6 +37,13 @@ type MapStateToProps<OwnProps = undefined> = ((global: GlobalState, ownProps: Ow
|
||||
|
||||
let currentGlobal = {} as GlobalState;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
let DEBUG_currentGlobalId: number | undefined;
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
const DEBUG_resetIdThrottled = throttleWithTickEnd(() => {
|
||||
DEBUG_currentGlobalId = Math.random();
|
||||
});
|
||||
|
||||
const actionHandlers: Record<string, ActionHandler[]> = {};
|
||||
const callbacks: Function[] = [updateContainers];
|
||||
const actions = {} as Actions;
|
||||
@ -61,6 +70,12 @@ function runCallbacks(forceOnHeavyAnimation = false) {
|
||||
|
||||
export function setGlobal(newGlobal?: GlobalState, options?: ActionOptions) {
|
||||
if (typeof newGlobal === 'object' && newGlobal !== currentGlobal) {
|
||||
if (DEBUG) {
|
||||
if (newGlobal.DEBUG_id !== DEBUG_currentGlobalId) {
|
||||
throw new Error('[TeactN.setGlobal] Attempt to set an outdated global');
|
||||
}
|
||||
}
|
||||
|
||||
currentGlobal = newGlobal;
|
||||
if (options?.forceSyncOnIOs) {
|
||||
runCallbacks(true);
|
||||
@ -71,6 +86,12 @@ export function setGlobal(newGlobal?: GlobalState, options?: ActionOptions) {
|
||||
}
|
||||
|
||||
export function getGlobal() {
|
||||
if (DEBUG) {
|
||||
DEBUG_currentGlobalId = Math.random();
|
||||
currentGlobal.DEBUG_id = DEBUG_currentGlobalId;
|
||||
DEBUG_resetIdThrottled();
|
||||
}
|
||||
|
||||
return currentGlobal;
|
||||
}
|
||||
|
||||
@ -80,12 +101,12 @@ export function getActions() {
|
||||
|
||||
function handleAction(name: string, payload?: ActionPayload, options?: ActionOptions) {
|
||||
actionHandlers[name]?.forEach((handler) => {
|
||||
const response = handler(currentGlobal, actions, payload);
|
||||
const response = handler(DEBUG ? getGlobal() : currentGlobal, actions, payload);
|
||||
if (!response || typeof response.then === 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
setGlobal(response, options);
|
||||
setGlobal(response as GlobalState, options);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
type Scheduler =
|
||||
typeof requestAnimationFrame
|
||||
| typeof onTickEnd
|
||||
| typeof runNow;
|
||||
| typeof onTickEnd;
|
||||
|
||||
export function debounce<F extends AnyToVoidFunction>(
|
||||
fn: F,
|
||||
@ -77,10 +76,6 @@ export function throttleWithTickEnd<F extends AnyToVoidFunction>(fn: F) {
|
||||
return throttleWith(onTickEnd, fn);
|
||||
}
|
||||
|
||||
export function throttleWithNow<F extends AnyToVoidFunction>(fn: F) {
|
||||
return throttleWith(runNow, fn);
|
||||
}
|
||||
|
||||
export function throttleWith<F extends AnyToVoidFunction>(schedulerFn: Scheduler, fn: F) {
|
||||
let waiting = false;
|
||||
let args: Parameters<F>;
|
||||
@ -109,10 +104,6 @@ export function onIdle(cb: NoneToVoidFunction, timeout?: number) {
|
||||
}
|
||||
}
|
||||
|
||||
function runNow(fn: NoneToVoidFunction) {
|
||||
fn();
|
||||
}
|
||||
|
||||
export const pause = (ms: number) => new Promise<void>((resolve) => {
|
||||
setTimeout(() => resolve(), ms);
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user