通过异步取消链接文件的文件夹非常慢
Unlinking a folder of files by async is super slow
我正在尝试调用一个 http 请求,该请求通过 fs
清空一个文件夹。我们假设没有子文件夹。因为forEach
不是异步的,所以我选择使用async
的each
而不是forEach
。代码如下:
后端:
router.post('/emptyDir', function (req, res, next) {
console.log("router.post /emptyDir");
var dir = req.body.dir;
var fs = require('fs');
var async = require('async');
fs.readdir(dir, function (err, files) {
if (err) return console.log(err);
console.log(JSON.stringify(files));
async.each(files, function (file) {
fs.unlink(dir + file, function (err) {
if (err) return console.log(err);
console.log(dir + file + " is removed");
})
}, function (err) {
if (err) return console.log('A file failed to be removed');
console.log('All files have been successfully removed');
return res.json(dir);
})
});
});
前端:
this.rewriteAllFiles = function (files) {
return $http.post('/emptyDir', { dir: prefix + idP + "/" })
.then(function (res) {
console.log("emptyDir finished");
...
我 运行 一个包含 2 个文件的文件夹的测试。它首先在浏览器日志中不显示任何内容,然后在后端显示以下日志:
router.post /emptyDir
["index.html","script.js"]
public/tmp/BGMTbU0RbeHdLAMjAAAD/index.html is removed
public/tmp/BGMTbU0RbeHdLAMjAAAD/script.js is removed
然后2分钟后,浏览器日志显示emptyDir finished
,后台再次显示router.post /emptyDir
:
router.post /emptyDir
[]
All files have been successfully removed
我不明白为什么/emptyDir
被调用了两次,为什么需要这么长时间...
所以有谁知道哪里错了吗?
编辑 1: 我意识到使用 Array.forEach
至少对我的测试有效。但我不确定它是否逻辑正确。 return 在 块 files.forEach
完成之前可以使用以下函数吗?
router.post('/writeFiles', function (req, res, next) {
console.log("router.post writeFiles");
var dir = req.body.dir, files = req.body.files;
var fs = require('fs');
files.forEach(function (file) {
fs.writeFile(dir + file.name, file.body, function (err) {
if (err) return console.log(err);
console.log(dir + file.name + " is written");
})
});
console.log("All files have been successfully written");
return res.json(dir);
})
Unlink 是异步的,所以你的整个 foreach 循环比你的代码的其余部分 运行 "at the same time" ].
我认为您可以考虑使用 Promises。您可以为每个取消链接的文件创建一个 Promise 数组。然后,您将使用 Promise.all().
等待所有 Promise 的完成(或失败)
类似的东西(它需要一些 "reorganisation" 但这是想法):
router.post('/emptyDir', function (req, res, next) {
console.log("router.post /emptyDir");
var dir = req.body.dir;
var fs = require('fs');
fs.readdir(dir, function (err, files) {
if (err) return console.log(err);
console.log(JSON.stringify(files));
var unlinkQueue = files.map(function(file) {
return new Promise(function(resolve, reject) {
fs.unlink(dir + file, function (err) {
if (err) return reject(err);
console.log(dir + file + " is removed");
resolve(file);
});
});
});
Promise.all(unlinkQueue)
.then(function(files) {
console.log("All files have been successfully removed");
res.json(dir);
})
.catch(function(err) {
/* error */
});
});
});
我发现,相对于the doc of async,我忘记了async.each(files, function(file, callback) ...)
中的callback
。以下代码有效:
router.post('/emptyDir', function (req, res, next) {
console.log("router.post /emptyDir");
var dir = req.body.dir;
var fs = require('fs');
var async = require('async');
fs.readdir(dir, function (err, files) {
console.log(JSON.stringify(files));
async.each(files, function (file, callback) {
fs.unlink(dir + file, function (err) {
if (err) {
console.log(err);
callback(err)
} else {
console.log(dir + file + " is removed");
callback();
}
})
}, function (err) {
if (err) return console.log('A file failed to be removed');
console.log('All files have been successfully removed');
return res.json(dir);
})
});
});
我正在尝试调用一个 http 请求,该请求通过 fs
清空一个文件夹。我们假设没有子文件夹。因为forEach
不是异步的,所以我选择使用async
的each
而不是forEach
。代码如下:
后端:
router.post('/emptyDir', function (req, res, next) {
console.log("router.post /emptyDir");
var dir = req.body.dir;
var fs = require('fs');
var async = require('async');
fs.readdir(dir, function (err, files) {
if (err) return console.log(err);
console.log(JSON.stringify(files));
async.each(files, function (file) {
fs.unlink(dir + file, function (err) {
if (err) return console.log(err);
console.log(dir + file + " is removed");
})
}, function (err) {
if (err) return console.log('A file failed to be removed');
console.log('All files have been successfully removed');
return res.json(dir);
})
});
});
前端:
this.rewriteAllFiles = function (files) {
return $http.post('/emptyDir', { dir: prefix + idP + "/" })
.then(function (res) {
console.log("emptyDir finished");
...
我 运行 一个包含 2 个文件的文件夹的测试。它首先在浏览器日志中不显示任何内容,然后在后端显示以下日志:
router.post /emptyDir
["index.html","script.js"]
public/tmp/BGMTbU0RbeHdLAMjAAAD/index.html is removed
public/tmp/BGMTbU0RbeHdLAMjAAAD/script.js is removed
然后2分钟后,浏览器日志显示emptyDir finished
,后台再次显示router.post /emptyDir
:
router.post /emptyDir
[]
All files have been successfully removed
我不明白为什么/emptyDir
被调用了两次,为什么需要这么长时间...
所以有谁知道哪里错了吗?
编辑 1: 我意识到使用 Array.forEach
至少对我的测试有效。但我不确定它是否逻辑正确。 return 在 块 files.forEach
完成之前可以使用以下函数吗?
router.post('/writeFiles', function (req, res, next) {
console.log("router.post writeFiles");
var dir = req.body.dir, files = req.body.files;
var fs = require('fs');
files.forEach(function (file) {
fs.writeFile(dir + file.name, file.body, function (err) {
if (err) return console.log(err);
console.log(dir + file.name + " is written");
})
});
console.log("All files have been successfully written");
return res.json(dir);
})
Unlink 是异步的,所以你的整个 foreach 循环比你的代码的其余部分 运行 "at the same time" ].
我认为您可以考虑使用 Promises。您可以为每个取消链接的文件创建一个 Promise 数组。然后,您将使用 Promise.all().
等待所有 Promise 的完成(或失败)类似的东西(它需要一些 "reorganisation" 但这是想法):
router.post('/emptyDir', function (req, res, next) {
console.log("router.post /emptyDir");
var dir = req.body.dir;
var fs = require('fs');
fs.readdir(dir, function (err, files) {
if (err) return console.log(err);
console.log(JSON.stringify(files));
var unlinkQueue = files.map(function(file) {
return new Promise(function(resolve, reject) {
fs.unlink(dir + file, function (err) {
if (err) return reject(err);
console.log(dir + file + " is removed");
resolve(file);
});
});
});
Promise.all(unlinkQueue)
.then(function(files) {
console.log("All files have been successfully removed");
res.json(dir);
})
.catch(function(err) {
/* error */
});
});
});
我发现,相对于the doc of async,我忘记了async.each(files, function(file, callback) ...)
中的callback
。以下代码有效:
router.post('/emptyDir', function (req, res, next) {
console.log("router.post /emptyDir");
var dir = req.body.dir;
var fs = require('fs');
var async = require('async');
fs.readdir(dir, function (err, files) {
console.log(JSON.stringify(files));
async.each(files, function (file, callback) {
fs.unlink(dir + file, function (err) {
if (err) {
console.log(err);
callback(err)
} else {
console.log(dir + file + " is removed");
callback();
}
})
}, function (err) {
if (err) return console.log('A file failed to be removed');
console.log('All files have been successfully removed');
return res.json(dir);
})
});
});