Использование промисов Bluebird в Node.JS

В моем приложении я пытаюсь прочитать файл, а затем записать содержимое файла в другой файл.

Для этого я использовал обещания bluebird. Мне нужна помощь, чтобы подтвердить правильность моего понимания использования промисов в моей реализации.

Вопросы, которые у меня есть,

  1. В моем примере я сначала читаю файл, затем, как только файл читает файл, я записываю содержимое в другой файл в своем следующем блоке «.then». После того, как содержимое записано в файл, мне нужно зарегистрировать сообщение. Я включил это во второй блок «.then». Мне нужно знать, правильно ли я понимаю обещания. будет ли второй блок «.then» работать как функция обратного вызова для оператора записи файла?

  2. Мне нужно писать более содержательные сообщения журнала. Различные сообщения об ошибках, если ошибка возникает при чтении файла и записи файла. Как я могу сделать это с блоками catch?

Заранее спасибо!

Пример кода ниже.

var Promise = require("bluebird");
var fs = Promise.promisifyAll(require("fs"));
var logger = require("./logger.js")
var projectJSON = require("../project.json");

var harPath = projectJSON.project.harfile.location;
var harFileNames = projectJSON.project.transactions.transactionsName;
var harFilePath;
var harFiles = {};
var writeFilePath = "../temp/"


harFileNames.forEach(function(harFileName){
    harFilePath = harPath + "/" + harFileName + ".har";

    fs.readFileAsync(harFilePath, "utf-8")
        .then(function(data){
            fs.writeFile(writeFilePath + harFileName + ".json", data);
            test = data;

        })
        .then(function(){
            console.log("data written successfully: ");

        })
        .catch(function(err){
            logger.error("error", "Error reading har files from location!");

        });

});

person nzhmz    schedule 09.10.2015    source источник


Ответы (1)


Если вы хотите фиксировать каждую ошибку отдельно, вы можете поместить обработчик ошибок сразу после каждой операции, чтобы вы могли напрямую фиксировать эту конкретную ошибку.

Затем, чтобы распространить ошибку, вы можете повторно выдать значение ошибки.

Затем вы хотите переключиться на fs.writeFileAsync(), чтобы все было асинхронно и использовало промисы.

Затем вам нужно вернуть обещание от fs.writeFileAsync().

var Promise = require("bluebird");
var fs = Promise.promisifyAll(require("fs"));
var logger = require("./logger.js")
var projectJSON = require("../project.json");

var harPath = projectJSON.project.harfile.location;
var harFileNames = projectJSON.project.transactions.transactionsName;
var harFilePath;
var harFiles = {};
var writeFilePath = "../temp/"


harFileNames.forEach(function(harFileName){
    harFilePath = harPath + "/" + harFileName + ".har";

    fs.readFileAsync(harFilePath, "utf-8")
        .then(function(data){
            harFiles[JSON.parse(data).log.pages[0].id] = JSON.parse(data);
            return data;
        }).catch(err) {
            logger.error("error", "Error reading har files from location!");
            throw err;      // propagate error
        }).then(function(data){
            return fs.writeFile(writeFilePath + harFileName + ".json", data).catch(function(err) {
                logger.error("error", "Error writing to harFile!");
                throw err;   // propagate error
            });
        }).then(function(){
            console.log("data written successfully: ");
        }).catch(function(err){
            // either one of the errors
        });

});

Имейте в виду, что когда у вас есть обработчик .catch(), ошибка считается «обработанной», и полученное обещание становится выполненным, а не отклоненным. Итак, если вы хотите зафиксировать ошибку в определенном месте (чтобы вы точно знали, откуда она взялась), но хотите, чтобы итоговое обещание оставалось отклоненным, вы можете либо вернуть отклоненное обещание, либо повторно сгенерировать ту же ошибку.


В соответствии с вашим дополнительным вопросом о том, как вернуть harFiles, вам понадобится окружающее обещание, которое будет разрешено с помощью harFiles, когда все будет сделано. Bluebird Promise.map() полезен для этого, поскольку он выполняет итерацию за вас и возвращает главное обещание. Вот как может выглядеть эта часть кода:

function someFunc() {

    var harPath = projectJSON.project.harfile.location;
    var harFileNames = projectJSON.project.transactions.transactionsName;
    var harFilePath;
    var harFiles = {};
    var writeFilePath = "../temp/"

    return Promise.map(harFileNames, function(harFileName) {
        harFilePath = harPath + "/" + harFileName + ".har";

        return fs.readFileAsync(harFilePath, "utf-8")
            .then(function(data){
                harFiles[JSON.parse(data).log.pages[0].id] = JSON.parse(data);
                return data;
            }, function(err) {
                logger.error("error", "Error reading har files from location!");
                throw err;      // propagate error
            }).then(function(data){
                return fs.writeFile(writeFilePath + harFileName + ".json", data).catch(function(err) {
                    logger.error("error", "Error writing to harFile!");
                    throw err;   // propagate error
                });
            }).then(function(){
                console.log("data written successfully: ");
            }).catch(function(err){
                // either one of the errors
            });

    }).then(function() {
        // all results are in harFiles array here
        return harFiles;
    });
}

someFunc().then(function(hFiles) {
    // hFiles should be your files object
});
person jfriend00    schedule 09.10.2015
comment
Спасибо за ваш ответ. В вашем примере вы добавили ошибки в каждый блок catch, чтобы отклонить полученные промисы, не так ли? Еще один вопрос. Этот блок кода находится внутри функции. Как только он прочитает все файлы и запишет их в новое место, как написано в примере, я хочу вернуть массив объектов harFiles. когда я включаю свою строку возврата после цикла for для каждого, он возвращает «undefined» из-за асинхронного поведения. Как я могу это сделать? - person nzhmz; 09.10.2015
comment
@Hamza - Да, строки throw err предназначены для того, чтобы убедиться, что результирующее обещание остается отклоненным, поэтому дальнейшие операции в этой цепочке не предпринимаются и чтобы причина отклонения дошла до конца. Я добавил еще один раздел в свой ответ о возвращении harFiles. - person jfriend00; 09.10.2015
comment
Огромное спасибо за помощь. - person nzhmz; 09.10.2015
comment
Я попробовал ваше второе решение, но оно не сработало для меня. чтобы проверить значения в моем объекте harFiles, я добавил цикл для вывода значений в разделе «затем», но это не сработало. - person nzhmz; 09.10.2015
comment
@Hamza - Вы использовали .then() при вызове содержащей функции. См. дополнительное объяснение, которое я добавил ко второму примеру кода в своем ответе. - person jfriend00; 09.10.2015
comment
Спасибо за обновление ответа. Мое фактическое требование состоит в том, что я экспортирую эту функцию с помощью «module.exports» и вызываю эту функцию в другом файле. - person nzhmz; 10.10.2015
comment
Затем вы должны поддерживать либо возврат обещания, либо вызов обратного вызова, чтобы получить окончательный результат из модуля. Мое предложение состоит в том, чтобы вернуть обещание и заставить вызывающую сторону использовать .then() для доступа к результатам, поскольку обещания теперь являются частью стандарта Javascript в будущем. - person jfriend00; 10.10.2015
comment
Большое спасибо за все ваши ответы. - person nzhmz; 11.10.2015