01.03.2024, 10:20
|
Аспирант
|
|
Регистрация: 02.11.2023
Сообщений: 30
|
|
class ApiWrapper {
#client
#connect
constructor() {
this.#client = new DummyClient()
this.#connect = this.#client.connect()
}
async doSomething() {
await this.#connect
this.#client.doSomething()
}
}
Сообщение от Aetae
|
ksa, На моём собесе ты бы получил маленький минус(не окончательный) за такое решение.:) Никакой элегантности, левые не нужные таймеры...
|
У ksa решение простое и читаемое, хоть далеко и не оптимальное.
У Вас же, Aetae, решение проигрывает в простоте и читаемости. Конечно, отчасти это вина первоначального кода, но здесь же не соревнование в скорости написания решений. Для оценки "элегантности" в контексте собеседования решение от самого интервьюера должно быть как минимум простым, читаемым и сопровождаемым.
|
|
01.03.2024, 10:32
|
|
CacheVar
|
|
Регистрация: 19.08.2010
Сообщений: 14,229
|
|
roland, во. Я теперь понял чего в супе не хватало...
Я как раз и не понимал как соединение можно сделать через конструктор.
|
|
01.03.2024, 14:11
|
Профессор
|
|
Регистрация: 04.12.2012
Сообщений: 3,795
|
|
Я бы сделал как-то так, но метод connect обертки у меня явно костыльный, т.к., имхо, хранить состояние соединения должен сам клиент, а не пытаться открыть соединение на каждый вызов метода `connect`:
interface IClient {
connect(): Promise<void>;
doSomething(): Promise<void>;
}
declare const DummyClient: new() => IClient;
class ApiWrapper {
#client!: IClient;
#connectionPromise: Promise<void> | null = null;
#connectionState: 'connected' | 'connecting' | 'disconnected' = 'disconnected';
constructor(client?: IClient) {
this.#client = client ?? new DummyClient();
}
async connect() {
if (this.#connectionState !== 'disconnected') {
return this.#connectionPromise;
}
this.#connectionState = 'connecting';
return this.#connectionPromise = this.#client.connect().then(v => {
this.#connectionState = 'connected';
return v;
}).catch(e => {
this.#connectionState = 'disconnected';
throw e;
});
}
async doSomething() {
await this.connect();
return this.#client.doSomething();
}
}
ts playground
|
|
02.03.2024, 13:02
|
|
Тлен
|
|
Регистрация: 02.01.2010
Сообщений: 6,590
|
|
Nexus, +.
ksa, ну вот примерно как Nexus бы сделал, только выкинул бы возврат оригинального connect (и занулял бы connectionPromise по завершению, чтоб не висело в памяти: что бы там оно не возвращало - оно нам не нужно с гарантией 99%). Ну и connectionPromise назвал бы pendingConnection или просто pending. Но это всё фигня. :)
Кстати нашёл пока лучшее применение chat gpt - придумывать названия переменным и функциям. Решил самую сложную задачу в программировании можно сказать.:)
P.S. В тему о промисах - знает кто-нить готовую либу с нормальной поддержкой, которая бы умела бы делать debounce асинхронной функции, но не простой, а чтоб если таймер вышел - он всё равно не позволял повторного запуска пока предыдущий асинхронный вызов не завершится. Т.е. допустим у нас
const debounced = debounce(async (arg) => {
console.log(arg);
await delay(1000);
}, 100);
debounced(1);
await delay(300);
debounced(2);
await delay(300);
debounced(3);
// большинство либ - 1, 2, 3
// иногда - 1, но это debounce, а throttle
// надо - 1, 3
Второй вариант который тоже нужен - более стандрантый, но споддрежкой AbortControler'a, чтоб если таймер вышел и снова вызвали когда предыдущий промис ещё идёт - тригеррил AbortControler.abort();:
// надо - 1/aborted, 2/aborted, 3
Сейчас пишу свою версию, но там не всё так просто..:)
__________________
29375, 35
Последний раз редактировалось Aetae, 02.03.2024 в 14:05.
|
|
03.03.2024, 10:50
|
|
CacheVar
|
|
Регистрация: 19.08.2010
Сообщений: 14,229
|
|
Пока мне больше всего нравится вариант от камрада roland.
|
|
03.03.2024, 21:01
|
|
Профессор
|
|
Регистрация: 25.10.2016
Сообщений: 1,012
|
|
Сообщение от Nexus
|
this.#client = client ?? new DummyClient();
|
имхо, плохая идея. Наметившееся соблюдение DIP сразу идет лесом.
а так, согласен. Хотя, возможно, connectionPromise лучше хранить вообще в самом клиенте. Типа, нужно новое подключение - создали новый клиент.
|
|
03.03.2024, 21:06
|
|
Профессор
|
|
Регистрация: 25.10.2016
Сообщений: 1,012
|
|
Сообщение от Aetae
|
// большинство либ - 1, 2, 3
// надо - 1, 3
|
т.е. в этом примере те либы рисуют 1, 2, 3 с интервалами 300 мс, а тебе нужно, чтобы сначала 2 встала на ожидание, потом её по-тихому сменила 3, и в итоге запустилась 3?
|
|
04.03.2024, 16:46
|
Профессор
|
|
Регистрация: 04.12.2012
Сообщений: 3,795
|
|
Сообщение от Alexandroppolus
|
имхо, плохая идея. Наметившееся соблюдение DIP сразу идет лесом.
|
Вот тут, откровенно, не понял. Как зависимость класса нарушает принцип инверсии зависимостей?
Или вы про дефолтное значение?
Если второе, то это из-за условий автора:
Сообщение от AlexandrDr
|
Исправлять можно только код внутри класса ApiWrapper.
|
|
|
04.03.2024, 17:29
|
|
Профессор
|
|
Регистрация: 25.10.2016
Сообщений: 1,012
|
|
Nexus,
а, точно. Не заметил этого странного условия про ApiWrapper.
да, я говорил про дефолтное значение.
|
|
04.03.2024, 19:27
|
|
Тлен
|
|
Регистрация: 02.01.2010
Сообщений: 6,590
|
|
Сообщение от Alexandroppolus
|
т.е. в этом примере те либы рисуют 1, 2, 3 с интервалами 300 мс, а тебе нужно, чтобы сначала 2 встала на ожидание, потом её по-тихому сменила 3, и в итоге запустилась 3?
|
Вроде так.
Я таки нашёл похожее на то что надо:
1й вариант с 1, 3: perfect-debounce.
Из минусов - промисы завершаются не по порядку: при завершении 1 и начале 3: "одновременно" отстреливаются все предыдущее debunced в порядке 2, 3, 1 с возвратом 1. (возврат 3 ждёт следующих обращений)
Поведение своеобразное, на на мои хотелки ложилось хорошо.
2й вариант с 1/aborted, 2/aborted, 3: awesome-debounce-promise
Только он не использует signal, а свой cancel который оставляет первые два в вечном pending. Довольно интересное, хотя и нишевое решение.
Вообще интересное исследование получилось, о том что разные люди хотят от казалось-бы простой штуки debounce.
В итоге всё равно самописку на signal использовал.
__________________
29375, 35
Последний раз редактировалось Aetae, 04.03.2024 в 19:29.
|
|
|
|