承诺代码被读取两次
Promise code are read twice
我使用以下代码读取 json 文件和 return 一个承诺
我有两个问题
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
为什么会发生以及如何避免?
- 在我放的地方
console.log("test2");
我需要调用事件
json 解析完成并且 return 在 json 对象之外(对调用者),当我添加最后一个 then
它不起作用(returned object is undefined), 知道怎么做吗?
UPDATE 我试着按照它不起作用...
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);
来解决它
现在我应该如何解决第一个问题 which method called twice
正如@jaromandaX 所说,您可能有两个 *.json
文件。尝试打印出文件名,它应该会变得更加明显。在这种情况下,.map
预计会被调用两次,每个文件一次。否则你将无法一起读取和解析两个文件。
如果你想让它在所有文件读取和解析完成后收敛到一个点,那么你需要在 .map
之后链接另一个 .then
。例如
return globAsync("folder/*.json")
.map(function(file) {
...
})
.then(function() {
obj.emit('ready');
});
编辑 在评论中回答你的问题。有几件事你应该记住。
- 在 promise 链中抛出错误将被 promise 捕获并将其发送到拒绝流中。如果您有兴趣以理想的方式获取自定义错误类型或打印堆栈跟踪,您可能仍会抛出错误。但大多数人更喜欢
return Promise.reject(error)
.
.map
中的任何拒绝都会将承诺链发送到拒绝流程。
- 在拒绝链内部,如果你想继续沿着拒绝流向下。您需要
return Promise.reject(error)
,否则如果您没有 return 拒绝对象,您可以将其带回解决流程。
如果您想单独处理每个错误,您可以这样做:
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');
});
我使用以下代码读取 json 文件和 return 一个承诺 我有两个问题
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
为什么会发生以及如何避免?
- 在我放的地方
console.log("test2");
我需要调用事件 json 解析完成并且 return 在 json 对象之外(对调用者),当我添加最后一个then
它不起作用(returned object is undefined), 知道怎么做吗?
UPDATE 我试着按照它不起作用...
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);
来解决它
现在我应该如何解决第一个问题 which method called twice
正如@jaromandaX 所说,您可能有两个 *.json
文件。尝试打印出文件名,它应该会变得更加明显。在这种情况下,.map
预计会被调用两次,每个文件一次。否则你将无法一起读取和解析两个文件。
如果你想让它在所有文件读取和解析完成后收敛到一个点,那么你需要在 .map
之后链接另一个 .then
。例如
return globAsync("folder/*.json")
.map(function(file) {
...
})
.then(function() {
obj.emit('ready');
});
编辑 在评论中回答你的问题。有几件事你应该记住。
- 在 promise 链中抛出错误将被 promise 捕获并将其发送到拒绝流中。如果您有兴趣以理想的方式获取自定义错误类型或打印堆栈跟踪,您可能仍会抛出错误。但大多数人更喜欢
return Promise.reject(error)
. .map
中的任何拒绝都会将承诺链发送到拒绝流程。- 在拒绝链内部,如果你想继续沿着拒绝流向下。您需要
return Promise.reject(error)
,否则如果您没有 return 拒绝对象,您可以将其带回解决流程。
如果您想单独处理每个错误,您可以这样做:
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');
});