You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用window.location.href下载文件时加载动画不生效问题排查

Why Your Loading Indicator Fails with window.location.href Downloads

Let's break down exactly why your loader isn't showing up here, and how to fix it:

The core problem is timing. When you use window.location.href to trigger a file download, your code runs in a strict synchronous sequence:

  1. You call indicatorStart() to add the loader to the DOM
  2. You tell the browser to fetch the file via window.location.href
  3. Immediately after, you call indicatorStop() to remove the loader

The browser doesn't get a chance to actually render the loader before it's deleted. Unlike AJAX requests (which are asynchronous, giving the browser time to paint the loader while waiting for a response), this entire sequence happens in a split second. Even if you didn't delete the loader right away, the browser might temporarily block DOM rendering while handling the file download request, so the loader still wouldn't appear.


Fixes to Try

1. Use Asynchronous Fetch + Blob Download (Most Reliable)

This approach gives you full control over the loader's lifecycle, and even lets you handle download errors gracefully. We'll fetch the file as a Blob, then create a temporary link to trigger the download:

$(document)
.off('click', '#btnExportToExcel')
.on('click', '#btnExportToExcel', async function (e) {
    e.preventDefault();
    indicatorStart('Loading');
    
    try {
        // Fetch the file asynchronously
        const response = await fetch('/Index/ExcelReport');
        if (!response.ok) throw new Error('Failed to load report');
        
        // Convert the response to a Blob
        const blob = await response.blob();
        
        // Create a temporary download link
        const downloadUrl = window.URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = downloadUrl;
        
        // Extract filename from backend's Content-Disposition header (if available)
        const contentDisposition = response.headers.get('Content-Disposition');
        if (contentDisposition) {
            const filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
            if (filenameMatch) {
                link.download = filenameMatch[1].replace(/['"]/g, '');
            }
        }
        
        // Trigger the download
        document.body.appendChild(link);
        link.click();
        
        // Clean up temporary resources
        window.URL.revokeObjectURL(downloadUrl);
        document.body.removeChild(link);
    } catch (error) {
        console.error('Download failed:', error);
        // Add custom error handling here (e.g., show a user-friendly toast)
    } finally {
        // Stop the loader once download completes (or fails)
        indicatorStop();
    }
});

Pros:

  • Loader stays visible until the download finishes (or fails)
  • Supports error handling for failed requests
  • Works consistently across all modern browsers

2. Add a Short Delay to indicatorStop() (Quick & Simple)

If you want to avoid rewriting your download logic, you can add a small timeout to give the browser time to render the loader before removing it. Note this is less reliable (timings vary by browser and network speed):

$(document)
.off('click', '#btnExportToExcel')
.on('click', '#btnExportToExcel', function (e) {
    e.preventDefault();
    indicatorStart('Loading');
    window.location.href = '/Index/ExcelReport';
    
    // Give the browser 300ms to render the loader before cleaning up
    setTimeout(() => {
        indicatorStop();
    }, 300);
});

Pros:

  • Minimal code changes required

Cons:

  • If the file downloads faster than the timeout, the loader will flash briefly
  • If the file takes longer to start downloading, the loader disappears early
  • No way to handle download failures

Why AJAX Works But This Doesn't

In AJAX scenarios, the request runs asynchronously: after calling indicatorStart(), the browser has time to render the loader while waiting for the server response. indicatorStop() only runs after the response comes back, so the loader stays visible for the full duration of the request. With window.location.href, there's no "wait for response" step—your code triggers the download and immediately cleans up the loader before anything can be rendered.

内容的提问来源于stack exchange,提问作者fingers10

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:36:55