这是我第一次使用promises,所以我使用bluebird
库来完成我的任务。在下面的代码中,我有来自客户端的字符串输入,我必须在fileSystem中搜索。所以我必须遍历dir并检查该字符串是否与任何文件相匹配,以便results
行,所以一旦forEach
完成,我想将results
发送给客户端。如何使用promises实现该任务?以下代码错误
Error: Unhandled rejection TypeError: expecting an array or an iterable object but got [object Null]
app.js
searchFileService.readFile(searchTxt, logFiles, function(lines, err) {
console.log('Logs', lines);
if (err)
return res.send();
res.json(lines);
})
promises.js
function readFile(str,logFiles,callback){
searchStr = str;
return Promise.map(logFiles, function(logfile) {
return new Promise(function(resolve, reject) {
fs.readFile('logs/dit/' + logfile.filename, 'utf8', function(err, data) {
if (err) {
callback(null,err);
return; // **** Make sure not to run the code below!
}
var lines = data.split('\n'); // get the lines
lines.forEach(function(line) { // for each line in lines
if (line.indexOf(searchStr) != -1) { // if the line contain the searchSt
results.push(line);
}
});
});
})
});
//}
}
Promise
.all(readFile())
.then(function() {
console.log('done');
callback(results);
});
答案 0 :(得分:1)
我发布了一些一般性建议,然后发布了一些代码示例非常复杂的答案,所以我想使用正确的模块添加readFiles()
函数可以非常紧凑:
function readFiles(str, files) {
return Promise.all(files.map(
file => rsp(fs.readFile(`logs/dit/${file}`, 'utf-8'))
.split('\n').filter(l => l.includes(str))))
.then(a => [].concat(...a));
}
这里正确的模块是mz
和rsp
(免责声明,我是rsp
模块的作者,因此我明显偏向于这里)。
mz
模块允许您使用承诺版本的fs
方法,而rsp
模块允许您在将来调用承诺结果的方法。
您需要将这些模块用作:
let fs = require('mz/fs');
let rsp = require('rsp');
上面的readFiles()
函数可以用作:
readFiles('line 3', ['file1.txt', 'file2.txt', 'file3.txt'])
.then(lines => console.log(lines.join('\n')))
.catch(err => console.log('Error:', err));
它确实有效 - 我用一堆文件测试了它logs/dit
目录。
let fs = require('mz/fs');
let rsp = require('rsp');
function readFiles(str, files) {
return Promise.all(files.map(
file => rsp(fs.readFile(`logs/dit/${file}`, 'utf-8'))
.split('\n').filter(l => l.includes(str))))
.then(a => [].concat(...a));
}
readFiles('line 3', ['file1.txt', 'file2.txt', 'file3.txt'])
.then(lines => console.log(lines.join('\n')))
.catch(err => console.log('Error:', err));
正如你所看到的,不需要循环,没有明确的回调,没有new Promise()
构造等。
如果要在Node中使用带有文件系统访问权限的Promises,请使用这些模块:
或者使用Bluebird的promisyfyAll:
宣传节点中的fs
模块。
例如,使用mz
,您可以执行以下操作:
return Promise.map(logFiles, file => fs.readFile('logs/dit/' + file, 'utf-8'));
在一行代码中返回所有这些文件内容的数组的承诺。
您可以进一步链接:
return Promise.map(...).then(files => ...);
获取所有文件并使用它们,或者您可以使用以下内容:
return Promise.map(logFiles, file => fs.readFile('logs/dit/' + file, 'utf-8').then(content => {...});
并且在转换后承诺提供一组文件内容。
答案 1 :(得分:0)
你忘了叫“解决”,你忘了传递参数,而你似乎正在使用“结果”作为全局变量,这很糟糕。
这是我对代码的更正:
function readFile(str,logFiles){
searchStr = str;
return Promise.map(logFiles, function(logfile) {
return new Promise(function(resolve, reject) {
fs.readFile('logs/dit/' + logfile.filename, 'utf8', function(err, data) {
if (err) {
reject(err);
return; // **** Make sure not to run the code below!
}
var results = [];
var lines = data.split('\n'); // get the lines
lines.forEach(function(line) { // for each line in lines
if (line.indexOf(searchStr) != -1) { // if the line contain the searchSt
results.push(line);
}
});
resolve(results);
});
})
});
}
Promise
.all(readFile(searchTxt, logFiles))
.then(function(results) {
console.log('done');
callback(results);
});
答案 2 :(得分:0)
错误 TypeError: expecting an array or an iterable object but got [object Null]
来自于logFiles
readFile()
来电Promise.map
,undefined
会对第一个参数{{1}感到不满}}
此外,您不能使用Promise.all(readFile(…))
,因为Promise.all
会承诺一系列承诺而非承诺(Promise.map
函数中的readFile
已经返回)。< / p>
但实际上,即使您修复了这些问题,您的代码仍然无效,因为您永远无法解决您创建的承诺。您需要实际调用reject
和resolve
,而不是某些callback
:
function readFile(filename) {
return new Promise(function(resolve, reject) {
fs.readFile(filename, 'utf8', function(err, data) {
if (err) reject(err); // <--
else resolve(data); // <--
});
});
}
现在您可以在循环中使用该功能:
function findFileLines(searchStr, logFiles) {
return Promise.map(logFiles, function(logfile) {
return readFile('logs/dit/' + logfile.filename).then(function(data) {
var lines = data.split('\n'); // get the lines
var result = lines.filter(function(line) {
return line.indexOf(searchStr) != -1
});
return result;
});
})
}
findFileLines("…", [{filename:"…"}, …]).then(function(results) {
console.log('done');
callback(results);
});