perf: embed shell soft nav, tab cache, and lighter options page boot
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
trade: "/trade",
|
||||
strategy: "/strategy",
|
||||
strategy_records: "/strategy/records",
|
||||
options: "/options",
|
||||
records: "/records",
|
||||
stats: "/stats",
|
||||
settings: "/settings",
|
||||
@@ -14,6 +15,7 @@
|
||||
|
||||
let navToken = 0;
|
||||
let loadingTab = false;
|
||||
const tabHtmlCache = new Map();
|
||||
|
||||
/** 自带校验后 form.submit() 的表单,勿在捕获阶段再 fetch 一份(会双发 POST) */
|
||||
const CUSTOM_SUBMIT_FORM_IDS = new Set(["add-order-form", "key-form", "roll-form"]);
|
||||
@@ -112,20 +114,61 @@
|
||||
});
|
||||
}
|
||||
|
||||
function embedPageUrl(tab) {
|
||||
const qs = listWindowQueryString();
|
||||
let url = "/api/embed/page/" + encodeURIComponent(tab);
|
||||
const parts = [];
|
||||
if (qs) parts.push(qs);
|
||||
parts.push("embed=1");
|
||||
return url + "?" + parts.join("&");
|
||||
}
|
||||
|
||||
async function fetchTabHtml(tab) {
|
||||
const r = await fetch(embedPageUrl(tab), {
|
||||
credentials: "same-origin",
|
||||
headers: { "X-Instance-Soft-Nav": "1" },
|
||||
});
|
||||
const j = await r.json();
|
||||
if (!j.ok || !j.html) throw new Error(j.msg || "加载失败");
|
||||
return j.html;
|
||||
}
|
||||
|
||||
function warmTabCache(tab) {
|
||||
if (!tab || tabHtmlCache.has(tab)) return;
|
||||
fetchTabHtml(tab)
|
||||
.then((html) => {
|
||||
tabHtmlCache.set(tab, html);
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
function clearTabCache() {
|
||||
tabHtmlCache.clear();
|
||||
}
|
||||
|
||||
async function loadTab(tab, opts) {
|
||||
const options = opts || {};
|
||||
if (!tab || loadingTab) return;
|
||||
const token = ++navToken;
|
||||
const force = !!options.force;
|
||||
const cached = !force && tabHtmlCache.get(tab);
|
||||
|
||||
if (cached) {
|
||||
injectFragment(cached);
|
||||
setNavActive(tab);
|
||||
if (!options.skipUrl) syncUrl(tab, !!options.replace);
|
||||
runPageInit(tab);
|
||||
warmTabCache(tab);
|
||||
return;
|
||||
}
|
||||
|
||||
loadingTab = true;
|
||||
setRootLoading(true);
|
||||
try {
|
||||
const qs = listWindowQueryString();
|
||||
const url = "/api/embed/page/" + encodeURIComponent(tab) + (qs ? "?" + qs : "");
|
||||
const r = await fetch(url, { credentials: "same-origin" });
|
||||
const html = await fetchTabHtml(tab);
|
||||
if (token !== navToken) return;
|
||||
const j = await r.json();
|
||||
if (!j.ok || !j.html) throw new Error(j.msg || "加载失败");
|
||||
injectFragment(j.html);
|
||||
tabHtmlCache.set(tab, html);
|
||||
injectFragment(html);
|
||||
setNavActive(tab);
|
||||
if (!options.skipUrl) syncUrl(tab, !!options.replace);
|
||||
runPageInit(tab);
|
||||
@@ -146,7 +189,8 @@
|
||||
}
|
||||
|
||||
function reloadCurrentTab() {
|
||||
return loadTab(getTab(), { replace: true, skipUrl: true });
|
||||
tabHtmlCache.delete(getTab());
|
||||
return loadTab(getTab(), { replace: true, skipUrl: true, force: true });
|
||||
}
|
||||
|
||||
function postFormAndReload(form, label) {
|
||||
@@ -172,6 +216,7 @@
|
||||
function patchApplyListWindow() {
|
||||
if (typeof global.applyListWindow !== "function") return;
|
||||
global.applyListWindow = function embedApplyListWindow() {
|
||||
clearTabCache();
|
||||
const qs = listWindowQueryString();
|
||||
const tab = getTab();
|
||||
const q = new URLSearchParams(qs);
|
||||
@@ -239,6 +284,9 @@
|
||||
|
||||
function bindNav() {
|
||||
document.querySelectorAll(".embed-top-nav [data-embed-tab]").forEach((a) => {
|
||||
a.addEventListener("mouseenter", () => {
|
||||
warmTabCache(a.getAttribute("data-embed-tab"));
|
||||
});
|
||||
a.addEventListener("click", (ev) => {
|
||||
ev.preventDefault();
|
||||
const tab = a.getAttribute("data-embed-tab");
|
||||
@@ -268,6 +316,7 @@
|
||||
reloadCurrentTab,
|
||||
getTab,
|
||||
postFormAndReload,
|
||||
clearTabCache,
|
||||
};
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
|
||||
Reference in New Issue
Block a user