Используя request.getAsync из bluebird, как «трубу» в файл - PullRequest
0 голосов
/ 08 сентября 2018

Я пытаюсь получить содержимое некоторого файла PDF асинхронно. Для этого я использую Promise.mapSeries с request.getAsync и spread из bluebird .

Но в then мне нужно получить результат этого request, используя pipe и createWriteStream напрямую. Что-то вроде:

request(url).pipe(fs.createWriteStream(file));

Это код, который я использую:

const Promise = require('bluebird');
const request = Promise.promisifyAll(require('request'), { multiArgs: true });
const fs = Promise.promisifyAll(require("fs"));

const urls = ['http://localhost/test-pdf/one.pdf', 'http://localhost/test-pdf/two.pdf'];

Promise.mapSeries(urls, url => {
    return request.getAsync({url: url, encoding:'binary'}).spread((response, body) => {
        if (response.statusCode == 200){
            let r = {};
            r.name = url.match(/\/([^/]*)$/)[1]; // get the last part of url (file name)
            r.content = body;
            console.log(`Getting ${r.name}`);
            return r;
        }
        else if (response.statusCode == 404){
            console.log(`The archive ${url.match(/\/([^/]*)$/)[1]} does not exists`);
        }
        else throw new Error(`Unsuccessful attempt. Code: ${response.statusCode}`);
    });
}).then((result) => {
    // Here I want to 'pipe' to a file the result from 'getAsync'
}).catch((error) =>{
    console.error(error);
})

Мой вопрос:

Как мне передать в файл результат из getAsync с помощью функции pipe? Это возможно?

PD: Я знаю, что могу использовать fs.promises, но просто хочу знать, возможно ли сделать это так, как я публикую

1 Ответ

0 голосов
/ 08 сентября 2018

Я думаю, что ответ уже в вопросе в том, что .then(), похоже, .pipe(), который вы ищете.

Чего не хватает, так это того, что (result) должно быть (results), т.е. массив всех пар {name, content}, возникающих из Promise.mapSeries(urls, ...).

Promise.mapSeries(urls, url => {
    return request.getAsync({'url':url, 'encoding':'binary'}).spread((response, body) => {
        if (response.statusCode == 200) {
            return {
                'name': url.match(/\/([^/]*)$/)[1], // get the last part of url (file name)
                'content': body
            };
        } else if (response.statusCode == 404) {
            throw new Error(`The archive ${url.match(/\/([^/]*)$/)[1]} does not exist`);
        } else {
            throw new Error(`Unsuccessful attempt. Code: ${response.statusCode}`);
        }
    });
}).then((results) => {
    // Here write each `result.content` to file.
}).catch((error) => {
    console.error(error);
});

На практике вы, вероятно, не захотите писать так, потому что каждая getAsync() должна быть завершена до начала какой-либо записи.

В большинстве случаев (и, вероятно, того, что вам нужно) лучше будет сделать так, чтобы содержимое каждого успешного getAsync() было записано как можно скорее:

Promise.mapSeries(urls, url => {
    let name = url.match(/\/([^/]*)$/)[1]; // get the last part of url (file name)
    return request.getAsync({'url':url, 'encoding':'binary'}).spread((response, body) => {
        if (response.statusCode == 200) {
            // write `body.content` to file.
        } else if (response.statusCode == 404) {
            throw new Error(`The archive ${name} does not exist`);
        } else {
            throw new Error(`Unsuccessful attempt. Code: ${response.statusCode}`);
        }
    });
}).catch((error) => {
    console.error(error);
});

Если пойти дальше, вы можете лучше обрабатывать ошибки, например, вы можете:

  • перехватить отдельные URL / ошибки получения / записи
  • компилировать статистику успеха / неудачи.

Нечто подобное может быть:

Promise.mapSeries(urls, url => {
    let name = url.match(/\/([^/]*)$/)[1] || ''; // get the last part of url (file name)
    if(!name) {
        throw new RangeError(`Error in input data for ${url}`);
    }
    return request.getAsync({'url':url, 'encoding':'binary'}).spread((response, body) => {
        if (response.statusCode == 200) {
            // write `body.content` to file.
            return { name, 'content': body };
        } else if (response.statusCode == 404) {
            throw new Error(`The archive ${name} does not exist`);
        } else {
            throw new Error(`Unsuccessful attempt. Code: ${response.statusCode}`);
        }
    })
    .catch(error => ({ name, error }));
}).then((results) => {
    let successes = results.filter(res => !res.error).length;
    let failures = results.filter(res => !!res.error).length;
    let total = results.length;
    console.log({ successes, failures, total }); // log success/failure stats
}).catch((error) => {
    console.error(error); // just in case some otherwise uncaught error slips through
});
...