I prefer axios over fetch because it treats bad server response status codes as errors out of the box, no need to add that in as one would have to do with fetch:
function getURL (url) {
return fetch(url)
.then((response) => {
if (!response.ok) {
throw new Error(response.statusText)
}
return response
})
}
The above boilerplate is not required when using modules like axios, as they tend to do this automatically.
With fetch, handling CORS is also a lot more difficult than with modules like axios.
As for progress tracking, remember that fetch is a lower-level API than XMLHttpRequest. If you want to observe progress, you would likely have to use the latter (although, streams will breathe progress tracking into the fetch api as soon as it lands).
For uploading files with XHR, it's pretty simple - track how big the file is, and how much has uploaded - calculate a percentage and you know your progress. For downloads, you'd have to read the Content-Length header from the server response and compare with how much has already been downloaded. You'd listen for these on xhr.upload.onprogress and xhr.onprogress for upload and download, respectively.
All of this is included out of the box in axios, however - so just use that. Don't fall victim to Not Invented Here syndrome.