Страница продолжает обновляться после fetch (). Then () с обещанием (установлен e.preventDefault ()) - PullRequest
0 голосов
/ 21 января 2020

Здравствуйте, я создаю простой API, используя ytdl с express, рассматриваемый маршрут загружает файл

app.post('/audio', (req, res) => {
    console.log(`Downloading audio from ${req.body.url}`);
    downloadAudio(req.body.url)
        .then(i => res.send())
        .catch(e => console.log(e));

    // setTimeout(() => {
    //     res.send();
    // }, 3000);
    // console.log('Audio');
    // console.log(req.body.url, ' - ', req.body.format);
});

Это функция загрузки аудио

const downloadAudio = url => {
    return new Promise((resolve, reject) => {
        ytdl.getInfo(url)
            .then(({ title }) => {
                const stream = ytdl(url);
                const proc = new ffmpeg({ source: stream });
                proc.save(`./public/downloads/${title}.mp3`);
                resolve();
                console.log(title);
            })
            .catch(error => {
                console.log('Custom error');
                reject(error);
            });
    });
};

проблема возникает из этой выборки

// 'http://localhost:5000/audio' is the first fetch argument
fetch(`${API_URL}/${format}`, {
        method: 'POST',
        body: jsonVideo,
        header: {
            'content-type': 'application/json',
        },
    })
        .then(res => {
            $button.textContent = 'Download';
            $button.removeAttribute('disabled');
            console.log('Done', res);
        })
        .catch(e => console.log(e));

После получения ответа страница просто перезагружается после выполнения того, что находится внутри then ()
На маршруте выше, если я использую setTimeout для тестирования, он ждет 3 секунд затем отправляет ответ, и программа работает, как и ожидалось, без обновления страницы, но если я использую обещания, она показывает ответ в devtools на секунду, но перезагружает страницу
Имейте в виду, у меня e.preventDefault() в первой строке прослушиватель событий, в который включена эта выборка.
https://github.com/jbordalo/youtube-dloader
Спасибо

Редактировать

app.post('/audio', (req, res) => {
    console.log('/AUDIO');
    console.log(`Downloading audio from ${req.body.url}`);

    res.send({ message: 'doing it' });

    // downloadAudio(req.body.url, (error, result) => {
    //     if (error) {
    //         console.log(error);
    //     } else {
    //         console.log(result);
    //         res.send({ message: result });
    //     }
    // });

});

Это работает, но если я раскомментирую downloadAudio и удаляю первую отправку, она снова начинает обновляться после ответ приходит на консоль (devtools)

1 Ответ

1 голос
/ 21 января 2020

При получении вы должны добавить два .then, один для преобразования возвращенного обещания в текст или json, а другой для фактического результата.

Так что вышеупомянутое следует исправить, выполнив :

fetch(`${API_URL}/${format}`, {
        method: 'POST',
        body: jsonVideo,
        header: {
            'content-type': 'application/json',
        },
    })
    .then(res=>res.json())
        .then(res => {
            $button.textContent = 'Download';
            $button.removeAttribute('disabled');
            console.log('Done', res);
        })
        .catch(e => console.log(e));

РЕДАКТИРОВАТЬ

Если это не сработает, вы всегда можете создать встроенный iframe, используя URL-адреса BLOB-объектов, извлечь данные в iframe и postMessage он возвращается на мэйнфрейм (и скрывает iframe от просмотра), таким образом, если страница обновляется, пользователь никогда не узнает. Например:

function c(s) {
    return s.split("&lt;").join("<").split("&gt;").join(">").split("&amp;").join("&")
}

var asdf = document.createElement("iframe");
asdf.src = URL.createObjectURL(new Blob([c(tt.innerHTML)], {
    type:"text/html"

}))
asdf.addEventListener("load", () => {
	asdf.contentWindow.postMessage(23, "*")
});
document.body.appendChild(asdf);
addEventListener("message", e => /*do something with fetched data */console.log(e.data))
<textarea style="display:none"id="tt">
	<b id="gf">asdf</b>
	<script>
	document.write(2134);
	window.addEventListener("message", e => {
		gf.innerHTML = Date.now();
		fetch(`${API_URL}/${format}`, {
			headers: {
				"content-type":"application/json"
				
			},
			method:"POST",
                    body: jsonVideo
		}).then(r=>r.text()).then(r => {
			
			e.source.postMessage(r);
		});
	})
	</script>
</textarea>
...