下面是我的代码片段:
var processListing = function (directoryItems) {
console.log('foreach');
var itemsToDownload = [];
directoryItems.forEach(function (element, index, array) {
//Ignore directories
if (element.type === 'd') {
console.log('directory ' + element.name);
return;
}
//Ignore non zips
if (path.extname(element.name) !== '.zip') {
console.log('ignoring ' + element.name);
return;
}
//Download zip
itemsToDownload.push({
source: element.name,
destination: element.name
});
//aftpSystem.downloadFile(element.name, element.name);
});
console.log('after foreach');
return itemsToDownload;
};
var getFiles = function () {
console.log('got files');
return fs.readdirAsync(process.cwd() + "/zips/").then(function (files) {
return files.filter(function (filename) {
return path.extname(filename) === '.zip';
});
});
};
aFtpClient. //this has been promisified
listAsync(). //so calls methodAsync
then(processListing).
map(function (object) {
return processItem(object).then(function (processResult) {
return {
input: object,
result: processResult
};
});
}).
map(function (downloadItem) {
console.log('downloading files');
downloadItem.result.once('close', function () {
console.log('closed');
});
return downloadItem.result.pipe(fs.createWriteStream(process.cwd() + "/zips/" + downloadItem.input.destination));
}).
then(getFiles).
我正在尝试使用承诺通过FTP下载项目。目前,它下载了第一个文件,但随后下载失败。我是新的节点,但相当有信心,我的第二个映射函数需要返回一个承诺,但我一直无法找出如何经过多次尝试。我正在使用bluebird
的承诺,但不能看到如何与它和流工作。
谢谢
我不知道你到底在哪里卡住了,但指出你在大致的方向应该足够了:
- 你有一个与管道和事件一起工作的接口
- 你需要承诺这个接口
所以你需要做的是:
- 查看下载的"完成"事件是什么
- 创建一个承诺并在该事件中解决它,在失败事件中拒绝它。
承诺可以通过几种方式完成:
-
通过promise库。Bluebird包含了一个非常聪明的承诺器,它使用依赖于JIT的动态代码生成——它非常快——但它是为NodeJS的"nodeback"情况而构建的。(即错误作为回调的第一个参数传递)
-
使用
Deferred
对象。一般来说,这种方式更容易出错。 -
在Bluebird中使用
Promise.method
,这对于承诺api很容易,但实际上不是我们这里的情况。 -
使用
Promise
构造函数。这就是我们要做的。
new Promise(function(resolve,reject){
resolve(); // this resolves the promise
reject(); // this rejets the promise
});
注意,承诺事件发射器只有在触发完成事件时才能正常工作,并且只触发一次。承诺是一次性的,一旦定下就无法改变状态。事件可以触发多次。承诺像"load"
事件或"finished"
事件这样的事情是完全可以的——但不要承诺重复多次的事情。
你的第二个映射应该是这样的:
map(function (downloadItem) {
console.log('downloading files');
downloadItem.result.once('close', function () {
console.log('closed');
});
var pipeAction = downloadItem.result.pipe(fs.createWriteStream(process.cwd() + "/zips/" + downloadItem.input.destination));
return new Promise(function(resolve,reject){
pipeAction.on("end",function(){ //waits for data to be consumed
// pipe has ended here, so we resolve the promise
resolve();
});
});
}).
通常应该将约定提取到专用方法中。例如,上面可以是promisifyPipe
或类似的
这是一个承诺的管道:
//example: promisified_pipe(foo, fs.createWriteStream(somepath))enter code here
function promisified_pipe(response, file) {
let ended = false;
return new Promise(function(resolve, reject) {
response.pipe(file);
function nice_ending() {
if (!ended) {
ended = true;
resolve();
}
}
function error_ending() {
if (!ended) {
ended = true;
reject("file error");
}
}
file.on('finish', nice_ending);
file.on('end', nice_ending);
file.on('error', error_ending);
file.on('close', error_ending);
}).finally(() => file.close())
}