Вот способ вручную обернуть операцию конвейера в обещание. К сожалению, большая часть этого - просто обработка ошибок, чтобы покрыть все возможные места, где может произойти ошибка:
const http = require('http');
const fs = require('fs');
const download = function(url, dest) {
return new Promise((resolve, reject) => {
const file = fs.createWriteStream(dest);
// centralize error cleanup function
function cleanup(err) {
reject(err);
// cleanup partial results when aborting with an error
file.on('close', () => {
fs.unlink(dest);
});
file.end();
}
file.on('error', cleanup).on('finish', resolve);
const request = http.get(url, function(response) {
if (response.status < 200 || response.status >= 300) {
cleanup(new Error(`Unexpected Request Status Code: ${response.status}`);
return;
}
response.pipe(file);
response.on('error', cleanup);
}).on('error', cleanup);
});
};
download(someURL, someDest).then(() => {
console.log("operation complete");
}).catch(err => {
console.log(err);
});
Это не ждет, пока файлы будут закрыты или удалены в условиях ошибки прежде, чем отклонить (полагая, что естькак правило, ничего конструктивного, если эти операции очистки все равно имеют ошибки). Если это необходимо, его можно легко добавить, просто вызвав reject(err)
из асинхронных обратных вызовов для этих операций очистки или используя версию этих функций fs.promises
и ожидая их.
Нескольковещи на заметку. В основном это обработка ошибок, потому что есть три возможных места, где могут быть ошибки, и для некоторых ошибок требуется некоторая очистка.
Добавлена необходимая обработка ошибок.
В исходном коде OP они вызывали file.close()
, но file
- это поток, и в writeStream нет метода .close()
. Вы вызываете .end()
, чтобы закрыть поток записи.
Вам также, вероятно, необходимо проверить наличие соответствующего response.status
, поскольку http.get()
по-прежнему возвращает объект ответа и поток, даже если статусэто что-то вроде 4xx или 5xx.