Настройка грузится быстро: список пользователей ЛК из кэша; морфинг — якорная привязка прокрутки
1) Страница «Настройка» висела до 10 с, когда ЛК ЕСИА Финанс медленный/недоступен: setupData синхронно тянул список пользователей из ЛК (lkUsersForSetup, таймаут 10 с). Теперь список берётся из кэша мгновенно, обновляется в фоне с коротким таймаутом (3 с); при недоступном ЛК показывается сохранённый список с пометкой. Страница больше не ждёт ЛК. 2) Морфинг карточки: добавлена якорная привязка — запоминаем верхний видимый блок и после обновления корректируем прокрутку, чтобы при изменении высоты карточек выше обзора вид не подпрыгивал (устраняет «прыгнула чуть выше»). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -174,12 +175,52 @@ func (h *setupHandlers) lkUsersSave(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// lkUsersForSetup — список для страницы настроек; ошибка базы — строкой, чтобы страница открылась.
|
||||
func lkUsersForSetup(rc *RuntimeConfig) ([]LKUser, string) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
// lkUsersCache — список пользователей ЛК для страницы «Настройка». Берётся из кэша (мгновенно),
|
||||
// обновляется в фоне с коротким таймаутом. Иначе медленный/недоступный ЛК вешал страницу на 10 с.
|
||||
var lkUsersCache struct {
|
||||
sync.Mutex
|
||||
list []LKUser
|
||||
errMsg string
|
||||
at time.Time
|
||||
refreshing bool
|
||||
}
|
||||
|
||||
func lkUsersRefresh(rc *RuntimeConfig) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
list, err := lkListUsers(ctx, rc)
|
||||
lkUsersCache.Lock()
|
||||
defer lkUsersCache.Unlock()
|
||||
lkUsersCache.refreshing = false
|
||||
lkUsersCache.at = time.Now()
|
||||
if err != nil {
|
||||
return nil, err.Error()
|
||||
if lkUsersCache.list != nil { // ЛК не ответил — оставляем прошлый список с пометкой
|
||||
lkUsersCache.errMsg = "ЛК сейчас недоступен — показан сохранённый список (" + err.Error() + ")"
|
||||
return
|
||||
}
|
||||
return list, ""
|
||||
lkUsersCache.errMsg = err.Error()
|
||||
return
|
||||
}
|
||||
lkUsersCache.list, lkUsersCache.errMsg = list, ""
|
||||
}
|
||||
|
||||
// lkUsersForSetup — список пользователей ЛК для страницы «Настройка»: отдаёт кэш сразу, при
|
||||
// устаревании обновляет в фоне (страница не ждёт ЛК). Первый раз (холодный кэш) — одно короткое ожидание.
|
||||
func lkUsersForSetup(rc *RuntimeConfig) ([]LKUser, string) {
|
||||
lkUsersCache.Lock()
|
||||
cold := lkUsersCache.at.IsZero()
|
||||
stale := time.Since(lkUsersCache.at) > 20*time.Second
|
||||
if !cold && stale && !lkUsersCache.refreshing {
|
||||
lkUsersCache.refreshing = true
|
||||
go lkUsersRefresh(rc)
|
||||
}
|
||||
list, msg := lkUsersCache.list, lkUsersCache.errMsg
|
||||
lkUsersCache.Unlock()
|
||||
if cold {
|
||||
lkUsersRefresh(rc) // первый заход — подождём коротко (≤3 с), дальше всегда из кэша
|
||||
lkUsersCache.Lock()
|
||||
list, msg = lkUsersCache.list, lkUsersCache.errMsg
|
||||
lkUsersCache.Unlock()
|
||||
}
|
||||
return list, msg
|
||||
}
|
||||
|
||||
@@ -893,9 +893,14 @@ button.dq-link, .dq-link { background:none !important; border:0 !important; padd
|
||||
.then(function(r){ return r.ok ? r.text() : Promise.reject(); })
|
||||
.then(function(html){
|
||||
if (dirty || (window.bjSelecting && window.bjSelecting())) return; // правит форму или выделяет — не трогаем
|
||||
// Якорь: верхний видимый блок — чтобы при изменении высоты карточек выше обзора
|
||||
// вид не «подпрыгивал». После морфинга вернём этот блок на то же место по вертикали.
|
||||
var anchor = null, aTop = 0, cards = document.querySelectorAll('main .card, main aside');
|
||||
for (var ci = 0; ci < cards.length; ci++) { var r = cards[ci].getBoundingClientRect(); if (r.bottom > 0) { anchor = cards[ci]; aTop = r.top; break; } }
|
||||
var doc = new DOMParser().parseFromString(html, 'text/html');
|
||||
bjMorphKids(document.querySelector('main'), doc.querySelector('main'));
|
||||
if (window.bjInitCopyBars) window.bjInitCopyBars();
|
||||
if (anchor && anchor.isConnected) { var d = anchor.getBoundingClientRect().top - aTop; if (d) window.scrollBy(0, d); }
|
||||
})
|
||||
.catch(function(){})
|
||||
.then(function(){ bjRefreshing = false; });
|
||||
|
||||
Reference in New Issue
Block a user