fix: a popup reload mid-refresh no longer logs the requests it cancels (closes #218)
Chrome cancels a closing popup's open requests just after pagehide, and in the page a cancelled fetch() fails with the same "Failed to fetch" as a server that cannot be reached. The home screen's transaction list and the balance refresh logged an error for each, and the e2e suite failed on them. The popup now aborts an AbortController on pagehide, and those failure reports check its signal first. End-to-end tests reload the popup with Blockscout held and require nothing logged, and fail the transaction list for real and require the failure reported; a unit test covers the balance refresh. The address and token screens and the new-wallet address scan are #475. Model: opus-5-5
This commit was merged in pull request #476.
This commit is contained in:
@@ -48,6 +48,14 @@ function renderWalletList() {
|
||||
home.render(ctx);
|
||||
}
|
||||
|
||||
// Aborted when the popup page goes away, closed or reloaded. Chrome then
|
||||
// cancels the requests the page still has open, and a cancelled fetch() fails
|
||||
// with the same "Failed to fetch" as a server that cannot be reached. pagehide
|
||||
// fires first, so code that reports a failed request checks this and stays
|
||||
// silent about one the page's own closing cancelled.
|
||||
const pageClosed = new AbortController();
|
||||
window.addEventListener("pagehide", () => pageClosed.abort());
|
||||
|
||||
let refreshInFlight = false;
|
||||
|
||||
// The ten-second refresh init() starts, stopped when the popup moves to the
|
||||
@@ -66,6 +74,7 @@ async function doRefreshAndRender() {
|
||||
state.blockscoutUrl,
|
||||
state.trackedTokens,
|
||||
state.networkId,
|
||||
pageClosed.signal,
|
||||
),
|
||||
]);
|
||||
state.lastBalanceRefresh = Date.now();
|
||||
@@ -87,6 +96,7 @@ async function doRefreshAndRender() {
|
||||
const ctx = {
|
||||
renderWalletList,
|
||||
doRefreshAndRender,
|
||||
pageClosed: pageClosed.signal,
|
||||
showAddWalletView: () => {
|
||||
pushCurrentView();
|
||||
addWallet.show();
|
||||
|
||||
@@ -225,6 +225,9 @@ async function loadHomeTxs(ctx) {
|
||||
homeTxs = merged.slice(0, 25);
|
||||
renderHomeTxList(ctx);
|
||||
} catch (e) {
|
||||
// Cancelled by the popup closing, not failed: see pageClosed in
|
||||
// src/popup/index.js.
|
||||
if (ctx.pageClosed.aborted) return;
|
||||
log.errorf("loadHomeTxs failed:", e.message);
|
||||
const list = $("home-tx-list");
|
||||
if (list) {
|
||||
|
||||
+17
-2
@@ -87,7 +87,15 @@ function rawUnits(value) {
|
||||
// way `holders` already is. Absence is never filled in here: this is the
|
||||
// upstream of every screen that displays a token amount, so a value invented
|
||||
// at this point is indistinguishable from a real one everywhere below it.
|
||||
async function fetchTokenBalances(address, blockscoutUrl, trackedTokens) {
|
||||
//
|
||||
// `signal`, passed by the popup, is aborted when the popup closes; a request
|
||||
// that fails after that was cancelled by the closing and is not logged.
|
||||
async function fetchTokenBalances(
|
||||
address,
|
||||
blockscoutUrl,
|
||||
trackedTokens,
|
||||
signal,
|
||||
) {
|
||||
try {
|
||||
const resp = await debugFetch(
|
||||
blockscoutUrl + "/addresses/" + address + "/token-balances",
|
||||
@@ -190,18 +198,22 @@ async function fetchTokenBalances(address, blockscoutUrl, trackedTokens) {
|
||||
}
|
||||
return balances;
|
||||
} catch (e) {
|
||||
log.errorf("fetchTokenBalances failed:", e.message);
|
||||
if (!signal?.aborted) {
|
||||
log.errorf("fetchTokenBalances failed:", e.message);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch ETH balances, ENS names, and ERC-20 token balances for all addresses.
|
||||
// `signal` is as for fetchTokenBalances().
|
||||
async function refreshBalances(
|
||||
wallets,
|
||||
rpcUrl,
|
||||
blockscoutUrl,
|
||||
trackedTokens,
|
||||
networkId,
|
||||
signal,
|
||||
) {
|
||||
log.debugf("refreshBalances start, rpc:", urlOrigin(rpcUrl));
|
||||
const provider = getProvider(rpcUrl, networkId);
|
||||
@@ -220,6 +232,7 @@ async function refreshBalances(
|
||||
log.debugf("ETH balance", addr.address, addr.balance);
|
||||
})
|
||||
.catch((e) => {
|
||||
if (signal?.aborted) return;
|
||||
log.errorf(
|
||||
"ETH balance failed",
|
||||
addr.address,
|
||||
@@ -243,6 +256,7 @@ async function refreshBalances(
|
||||
);
|
||||
})
|
||||
.catch((e) => {
|
||||
if (signal?.aborted) return;
|
||||
log.errorf(
|
||||
"ENS reverse failed",
|
||||
addr.address,
|
||||
@@ -258,6 +272,7 @@ async function refreshBalances(
|
||||
addr.address,
|
||||
blockscoutUrl,
|
||||
trackedTokens,
|
||||
signal,
|
||||
).then((balances) => {
|
||||
if (balances !== null) {
|
||||
addr.tokenBalances = balances;
|
||||
|
||||
Reference in New Issue
Block a user