rundll32
@rundll32

Неправильно работает задержка перед загрузкой файлов?

Есть цикл, который перебирает ссылки на картинки и отправляет их в метод Download (взятый со StackOverflow), который заставляет браузер их скачивать.
function Download(url, name) {
        fetch(url)
            .then(resp => resp.blob())
            .then(blob => {
                const url = window.URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.style.display = 'none';
                a.href = url;
                // the filename you want
                a.download = name;
                document.body.appendChild(a);
                a.click();
                window.URL.revokeObjectURL(url);
            })
            .catch(() => alert("Ошибка загрузки файла"));

Перед вызовом метода я пробовал разные способы создать ожидание, всякие while, которые ждут, пока пройдет нужное количество миллисекунд, но задержка всегда срабатывает только для первого элемента. Это приводит к тому, что файлы скачиваются в разном порядке, хотя все логи говорят, что массив правильно отсортирован. Так же и если после вызова, будто цикл все равно срабатывает без задержки. Потом я нашел такое решение-обертку для вызова:
function DownloadWorker(url, name) {
        setTimeout(function() {
            Download(url, name);
        }, DELAY);
    }

Где DELAY - константа. Но результат тот же, задержка есть только в начале, и файлы идут вперемешку.
  • Вопрос задан
  • 131 просмотр
Решения вопроса 1
@GrayHorse
Раз:
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

Два:
function download(blob, name, url) {
    const anchor = document.createElement("a");
    anchor.setAttribute("download", name || "");
    const blobUrl = URL.createObjectURL(blob);
    anchor.href = blobUrl + (url ? ("#" + url) : "");
    anchor.click();
    setTimeout(() => URL.revokeObjectURL(blobUrl), 5000);
}

Рекомендую добавлять оригинальную ссылку url (третий параметр) к blobUrl , может потом пригодиться — посмотреть, откуда (по какой именно ссылке) файл был скачен.
Например:
blob:https://imgur.com/11fb6df9-e45b-4acf-b3eb-60d5d4656747#https://i.imgur.com/X92aA5Y.jpeg


Вместе:
for (const url of urls) {
    const resp = await fetch(url);
    const blob = await resp.blob();
    const name = new URL(url).pathname.match(/[^\/]*$/)[0];
    download(blob, name, url);
    await sleep(200);
}
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
zkrvndm
@zkrvndm
Архитектор решений
Метод у вас кривой. Используйте async / await если хотите скачивать файлы последовательно:
Развернуть пример
async function downloadFiles(links) {
	
	for (var n = 0; n < links.length; n++) {
		
		try {
			
			var blob = await (await fetch(links[n])).blob();
			var blob_url = URL.createObjectURL(blob);
			var blob_name = new URL(links[n]).pathname.split('/').pop();
			
			var a = document.createElement('a');
			a.style.display = 'none';
			a.href = blob_url;
			
			a.setAttribute('download', blob_name);
			
			document.body.appendChild(a);
			a.click();
			
			console.log('Файл '+links[n]+' скачан');
			
			// Делаем задержку на 2 секунды:
			
			await new Promise(function(s) {
				setTimeout(s, 2000);
			});
			
			URL.revokeObjectURL(blob_url);
			
		}
		
		catch(err) {
			
			console.log('Ошибка, не удалось скачать файл ' + links[n]);
			console.erroe(err);
			
			// Делаем задержку на 2 секунды:
			
			await new Promise(function(s) {
				setTimeout(s, 2000);
			});
			
		}
		
	}
	
	console.log('Загрузка файлов завершена!');
	
}

Чтобы скачать файлы по ссылкам просто вызываете функцию downloadFiles передав в него массив ссылок:
downloadFiles([
    'https://i.imgur.com/X92aA5Y.jpeg', 
    'https://i.imgur.com/X92aA5Y.jpeg',
    'https://i.imgur.com/X92aA5Y.jpeg'
]);
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы