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