Javascript 为什么承诺先解决?
根据stackoverflow上的代码片段,我想读取目录中的所有文件,然后继续。 我加了一个承诺,但不知怎么的,这不起作用 我的目录包含2个文件,控制台日志输出为:Javascript 为什么承诺先解决?,javascript,promise,Javascript,Promise,根据stackoverflow上的代码片段,我想读取目录中的所有文件,然后继续。 我加了一个承诺,但不知怎么的,这不起作用 我的目录包含2个文件,控制台日志输出为: 承诺已解决 内部文件名 内部文件名 内部读取文件 内部读取文件 function readFiles(dirname, onFileContent, onError) { return new Promise((resolve, reject) => { fs.readdir(dirname, func
承诺已解决
内部文件名
内部文件名
内部读取文件
内部读取文件
function readFiles(dirname, onFileContent, onError) {
return new Promise((resolve, reject) => {
fs.readdir(dirname, function(err, filenames) {
filenames.forEach(function(filename) {
console.log('inside filenames');
fs.readFile(dirname + filename, 'utf-8', function(err, content) {
onFileContent(filename, content);
});
});
});
});
}
var data = [];
readFiles('datadir/', function(filename, content) {
console.log('inside readFiles');
data.push(filename);
}).then(
console.log('promise resolved');
//proceed handling the data-array
);
承诺不是“先解决”。对console.log
的调用在读取第一个文件之前执行
你永远不会按照你的承诺打电话给resolve
,所以然后
就永远不会被打电话了。但是,您正在将console.log的结果传递给然后
。console.log
的结果无效
您可以通过更正问题来测试这一点:
readFiles('datadir/', function(filename, content) {
console.log('inside readFiles');
data.push(filename);
}).then(function(){ // NOTE: addition of function(){..}
console.log('promise resolved');
//proceed handling the data-array
});
您会注意到消息从未写入控制台
这就是问题所在——如何修复它。在node中完全基于异步/承诺的代码需要一些思考
我假设您希望在解决您的承诺之前,等待所有文件的内容被读取。这有点棘手,因为您有两个异步调用(读取文件列表,然后分别读取其内容)。将文件的读取封装到自己的承诺中可能更容易。大概是这样的:
function readFile(filePath){
return new Promise((resolve,reject) => {
fs.readFile(filePath, "utf-8", function(err,content) => {
if(err) reject(err)
else resolve({path:filePath, content:content})
});
});
}
对readdir
执行相同操作,以使其也可链接:
function readDirectory(dir){
return new Promise((resolve,reject) => {
fs.readdir(dirname, function(err, filenames) {
if(err) reject(err);
else{
resolve(filenames.map(fn => dir + fn));
}
});
});
}
这样做的原因是,您可以使用Promise.all
来等待所有文件内容
function readFileContents(dirname) {
return readDirectory(dirname)
.then(files =>
Promise.all(files.map(file => readFile(file))
);
}
用法:
readFileContents('datadir/').then(files => {
files.forEach(file => {
console.log(file.path, file.content.length);
});
});
您的代码甚至不会用分号执行,但看起来您应该有then(function(){
而你只有然后
。假设你的真实代码中没有分号,这就是解释。我看不出你承诺的意义-你永远都不会解决它,你使用回调来获取文件内容。@Jamiec承诺的意义是等到所有文件都被读取。我明白了,但你是从来没有这样做过。你想让这个承诺成为正确的基础吗?是的,我不知道该把决心放在哪里(),不能把我的头缠绕在它周围。避免使用inreadFiles
!你应该使用promise构造函数创建一个readDir
函数,然后将它与readFile
正确地结合到readFiles
@Bergi中-我想这就是我用readFile
方法所做的。你能解释一下你的意思吗“使用承诺构造函数”?我写的两个方法只是简单的promise
包装了一个没有承诺接口的api调用。我看不出有什么危害,但可能我误解了。问题是它不仅包装了api调用,而且还包装了promise.all(…)
东西(而且确实处理错了)。你应该像对待readFile
一样,在fs.readdir
调用帮助函数时,考虑到promise包装器。promise。所有(…)
都需要放入。然后(…)
回调。@jamice谢谢,太好了!