0

I have a script that fetches urls and downloads images. It works fine with most servers, but for some of them the request will remain pending if the tab is not the active one (lets say, I switch windows, or move to some other app). When that tab gets focus, it will continue downloading (I noticed some gaps between requests, as seen in picture). When tab has focus, they would be no gaps. enter image description here

I use chrome 89.0.4389.114 (64 bits). Didn't try with other navigators.

Is there any kind of lazy fetching (for Chrome tabs) working here?


Update:

Usage: downloadAllImages({thumbs});

const downloading = []; 
const downloadErrors = []; 

// thumbs is a set of links with an image as child, like "<a href='http:...'><img src='http:..'></a>"
const thumbs = Array.from(document.querySelectorAll(".thumb")).map(thumb => {
    const img = thumb.querySelector("img"); 
    
    img.addEventListener("error", e => {
      img.src = "/img/404.png"; 
    });
    
    img.addEventListener("click", e => {
        e.preventDefault(); 
        e.stopPropagation();
        console.log(img);  
    }); 
    const opaque = thumb.querySelector(".opaque") ; 

    if (img.complete) {
        if (opaque) opaque.style.height = `${img.height}px`; 
        thumb.style.opacity = 1; 
    }
    else {
        img.addEventListener("load", e => {
            if (opaque) { 
                const rects = img.getClientRects()[0]; 
                opaque.style.height = `${rects.height}px`; 
            }
            thumb.style.opacity = 1; 
        }); 
    }
    thumb.addEventListener("click", e => {
        e.preventDefault(); 
        e.stopPropagation(); 
    }); 
    return thumb; 
});
        
async function downloadAllImages({thumbs}) {
    let i = 0; 
    
    while (thumbs[i]) {
        const elem = thumbs[i]; 
        
        if (!Number(elem.getAttribute('data-local'))) {
            if (downloadErrors.length > 3) break; 
            while (downloading.length > 3) await timeout(500); 
            downloadImage({elem, i}); 
        }
        
        i++; 
    }

    while(downloading.length) await timeout(1000); 
    console.log('done'); 
}

async function downloadImage({elem, i}) {
    downloading.push(elem); 
    showDownloadingAnimation({elem, i}); 
    
    const body = [
        { name: 'index', value: i },
        { name: 'src', value: elem.querySelector("img").src },
        { name: 'href', value: elem.href },
        { name: 'location', value: viperg.location },
    ].map(e => {
        return `${e.name}=${e.value}`;
    }).join("&");
    
    let r = await fetch(`/images/download`, createOptions({ body }));
    // images/download is pretty simple. I use Guzzle::HTTP to retrieve the contents for cettain url
    
    if (r.ok) {
        r = await r.json();
        
        if (r.filename) {
            let filename = r.filename; 
            r = await modifyJSONGallery({ index: i, attributes: [{ p: 'main', v: r.filename }] });
            
            if (r) { 
                downloading.pop(); 
                elem.querySelector(".opaque").classList.add('animateHeight'); 
                removeDownloadingAnimation({elem}); 
                elem.href = `http://wpcontent/${viperg.location}/i-${filename}`; 
                elem.querySelector("img").src = `http://wpcontent/${viperg.location}/t-${filename}`; 
                return 1; 
            }
        }
    }
    
    downloading.pop(); 
    removeDownloadingAnimation({elem}); // a simple png, with no animation 
    showDownloadingError({elem}); 
    downloadErrors.push(elem);
    
    return 1; 
}
async function modifyJSONGallery({index = -1, attributes = {}} = {}) {
    const body = `index=${index}&location=${viperg.location}&attrs=${JSON.stringify(attributes)}`; 
    
    let r = await fetch(`/galleries/modifyjsongallery`, createOptions({ body }));
    if (r.ok) {
        r = await r.json(); 
        if (r.s) return 1; 
    }
    return 0; 
}

function timeout(time) {
    return new Promise(resolve => setTimeout(resolve, time));
}

As read in post recommended by @esqew, I had some animation that used keyframes. I tried removing them, but there was no change (I left the animation disabled):

Test Two

Another way to test it is to log the timestamp repeatedly with setInterval and requestAnimationFrame and view it in a detached console. You can see how frequently it is updated (or if it is ever updated) when you make the tab or window inactive.

Results

Chrome ... requestAnimationFrame is paused when the tab is inactive.

  • It's hard to say exactly why this is occurring in *your* specific situation, as you haven't provided a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example). It may be related to the issues discussed in this SO thread: [How do browsers pause/change Javascript when tab or window is not active?](https://stackoverflow.com/questions/15871942/how-do-browsers-pause-change-javascript-when-tab-or-window-is-not-active) TL;DR: Chrome limits the execution of any code called using `setInterval()` with an interval value of < 1s when the tab is not active. – esqew Apr 12 '21 at 19:53
  • Thx! I added part of the script. Didn't add the php code, since when tab is active, that code will always run smooth (might fail due to not found url, but will never take more than 15 sec to bring a result). I have Laravel as backend. – Jesus Toledo Apr 13 '21 at 17:17
  • https://stackoverflow.com/questions/6032429/chrome-timeouts-interval-suspended-in-background-tabs – epascarello Apr 13 '21 at 17:23
  • @epascarello For what I read from the article, the setTimeout execution should slow down, but in my particular case fetch requests will stop completely if the tab lost focus (you can see in the image description). I will read about webworkers to see if that would help. – Jesus Toledo Apr 13 '21 at 18:10

0 Answers0