Wait for user to finish downloading a blob in Javascript
Asked Answered
G

1

5

In Javascript, I'm creating a number of blobs that I want to prompt the user to save as files. At the moment, I'm doing that using URL.createObjectURL, placing the URL in a link, and simulating a click to the link. (Of course I call URL.revokeObjectURL to release the URL so the blob can be discarded after the user saves it.) I have a loop that runs through and does this for each blob I want the user to save.

At least on Firefox, triggering the link is an asynchronous operation; I call click() and my loop to generate the rest of the blobs immediately continues execution before the user chooses a location to save the file.

This presents a bit of a problem because each blob could be somewhat large, and there could be a lot of them. I can easily foresee a situation where there wouldn't be sufficient memory to hold all of them in memory waiting for the user to save and release them one-by-one. So I'd like to generate one blob, have the user download it, and then, after the file has been saved (and thus is eligible to be discarded by the garbage collector), proceed to generate the next blob and have the user save it.

Is there any way to achieve this without requiring the user to manually click another button or some such thing to signal the page that he is done saving the file?

Grimsley answered 22/3, 2015 at 21:48 Comment(3)
Is utilizing jQuery library option ?Millwright
I know its a bit late but did you ever figure something out here? I do the exact same to save some binary data in my web-app, and i would like to revoke the buffer when saving is done. It actually stays in memory while the webpage is active - so the data object-url's reference wont be released until the user leaves the page or its closed.Montelongo
Unfortunately no. I got some suggestions elsewhere about using the window's focus event, but I was never able to get it to work predictably. Not sure if there have been any developments in the past couple years that would allow for this, but that's where I left off. Sorry. :-(Grimsley
E
4

This is what worked for me.

/**
 *
 * @param {object} object A File, Blob, or MediaSource object to create an object URL for. https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
 * @param {string} filenameWithExtension
 */
function saveObjectToFile (object, filenameWithExtension) {
  console.log('saveObjectToFile: object', object, 'filenameWithExtension', filenameWithExtension)
  const url = window.URL.createObjectURL(object)
  console.log('url', url)
  const link = document.createElement('a')
  link.style.display = 'none'
  link.href = url
  link.target = '_blank'
  link.download = filenameWithExtension
  console.log('link', link)
  document.body.appendChild(link)
  link.click()
  window.setTimeout(function () {
    document.body.removeChild(link)
    window.URL.revokeObjectURL(url)
  }, 0)
}

/**
 * @param {string} path
 * @param {object} payload
 * @param {string} filenameWithExtension
 * @returns {promise}
 */
export async function downloadFileInBackground (path, payload, filenameWithExtension) {
  console.log('downloadFileInBackground awaiting fetch...')
  const response = await fetch(path, {
    method: 'POST',
    cache: 'no-cache',
    headers: {
      'Content-Type': 'application/json'
    },
    body: payload // body data type must match "Content-Type" header
  })
  console.log('response', response)
  const blob = await response.blob()
  saveObjectToFile(blob, filenameWithExtension)
  console.log('downloadFileInBackground finished saving blob to file!', filenameWithExtension)
}

I know other people have this problem too:

P.S. I appreciate the idea from @sicking at https://github.com/whatwg/html/issues/954#issue-144165132.

Eikon answered 1/4, 2021 at 13:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.