Promise代码被读取两次

时间:2015-08-03 06:53:53

标签: javascript promise bluebird

我使用以下代码读取json文件并返回一个promise  我有两个问题

return globAsync("folder/*.json").catch(function (err) {
    throw new Error("Error read: " + err);
}).map(function (file) {
    return fs.readFileAsync(file, 'utf8')
        .then(function (res) {
            console.log("test");
            return JSON.parse(res); 
        },
        function (err) {
            throw new Error("Error :" + err);
        }).then(function () {
            console.log("test2");
        });
});

我使用控制台日志,我看到控制台打印了两次

test
test
test2
test2

为什么会发生这种情况以及如何避免它?

  1. 在我放置console.log("test2");的地方,我需要调用事件 json解析完成后仍然返回json对象外部(调用者),当我添加最后then它没有工作(返回的对象未定义)时,任何想法如何做到这一点对?
  2. 更新我尝试按照以下方式进行操作......

    return globAsync("folder/*.json").catch(function (err) {
                throw new Error("Error read: " + err);
            }).map(function (file) {
                return fs.readFileAsync(file, 'utf8')
                    .then(function (res) {
                        console.log("test");
                        JSON.parse(res); //data parse
                    }.catch(function (err) {
                            throw new Error("Error :" + err);
                        }
                    ).then(function (data) {
                            obj.emit('ready');
                            return data;
                        }))
            });
        }
    

    UPDATE2 我只需添加新的return JSON.parse(res);即可解决问题 现在我应该如何解决第一个问题调用两次

1 个答案:

答案 0 :(得分:0)

就像@jaromandaX所说,你可能有两个*.json个文件。尝试打印出文件名,它应该变得更加明显。在这种情况下,.map预计将被调用两次,每个文件一次。否则你将无法一起阅读和解析两个文件。

如果要在所有文件读取和解析完成后将其收敛到单个点,则需要在.then之后链接另一个.map。例如

return globAsync("folder/*.json")
    .map(function(file) {
        ...
    })
    .then(function() {
        obj.emit('ready');
    });

编辑在评论中回答您的问题。你应该记住一些事情。

  1. 承诺链中的投掷错误将被承诺捕获并将其发送到拒绝流程中。如果您有兴趣以理想的方式获取自定义错误类型或打印堆栈跟踪,则仍可能抛出错误。但大多数人更喜欢return Promise.reject(error)
  2. .map中的任何拒绝都会将承诺链发送到拒绝流程。
  3. 在拒绝链中,如果你想继续拒绝拒绝流程。您需要return Promise.reject(error),否则如果您没有返回拒绝对象,则可以将其恢复到解决流程中。
  4. 如果您想单独处理每个错误,可以执行以下操作:

    return globAsync("folder/*.json")
        .catch(function(error) {
            // TODO: Handle error
            return Promise.reject(error);
        })
        .map(function(file) {
            return fs.readFileAsync(file, 'utf8')
                .catch(function(error) {
                    // TODO: Handle error
                    return Promise.reject(error);
                })
                .then(function(res) {
                    return JSON.parse(res);
                });
        })
        .then(function() {
            obj.emit('ready');
        });
    

    如果你想为glob处理一次,为了文件读取而处理一次,那么你必须更有创意。

    return globAsync("folder/*.json")
        .catch(function(error) {
            // TODO: Handle error
            return Promise.reject(error);
        })
        .then(function(files) {
            return Promise.resolve(files)
                .map(function(file) {
                    return fs.readFileAsync(file, 'utf8');
                })
                .catch(function(error) {
                    // TODO: Handle error once for any read error
                    return Promise.reject(error);
                })
                .map(function(res) {
                    // Judging by your original code, you are not handling
                    // parser error, so I wrote this code to behave equivalent
                    // to your original. Otherwise chain parse immediate after
                    // readFileAsync.
                    return JSON.parse(res);
                });
        })
        .then(function() {
            obj.emit('ready');
        });