我正在尝试实现多个异步调用,并且仅在完成所有操作后才继续。
过程是这样的,我需要按此顺序完成: 获取文件路径列表, 将它们复制到新目的地, 转换位图, 创建缩略图, 将信息添加到Array中以批量插入DB
为此,我使用了promises数组和Promise.all()方法。此方法过早触发,因为当promise阵列尚未(完全)填充时会执行此方法。 如果我在for循环之后延迟一段时间它可以工作,但所需的时间取决于文件的数量。
这是主要的电话:
queueFiles(files).then(function () {
// Add to DB
console.log(current_import.sql.length); // Number of all datasets (0 at runtime)
console.log(current_import.sql); // An array of datasets ([] at runtime)
});
这是不能按预期工作的功能:
let import_promises = {
copy_promises : [],
convert_promises : [],
thumbnail_promises : [],
sql_promises : []
};
function queueFiles(files) {
return new Promise(function (resolve, reject) {
try {
for (file of files) {
let original_filename = file.split("\\").pop();
let original_extension = original_filename.split(".").pop();
let hashed_name = crypto.createHmac('sha256', secret).update(original_filename).digest('hex') + "." + original_extension;
let new_path = data_folder + "/" + hashed_name;
import_promises.copy_promises.push(fs.copy(file, new_path).then(function () {
if (original_extension == "bmp") {
import_promises.convert_promises.push(convertFile(new_path).then(function (result) {
import_promises.thumbnail_promises.push(createThumbnail(result.path, thumb_folder + "/" + result.path.split("/").pop(), 500).then(function () {
import_promises.sql_promises.push(addSql(result.data));
}));
}));
} else {
import_promises.thumbnail_promises.push(createThumbnail(new_path, thumb_folder + "/" + hashed_name, 500).then(function () {
import_promises.sql_promises.push(addSql(new_path));
}));
}
}));
}
Promise.all([import_promises.copy_promises, import_promises.convert_promises, import_promises.thumbnail_promises, import_promises.sql_promises])
.then(() => {
// All files copied, converted, thumbnails created and prepared to insert into DB
resolve();
});
}
catch (err) {
reject(err);
}
});
}
这些是辅助功能:
function createThumbnail(input, output, width) {
return new Promise(function (resolve, reject) {
try {
gm(input)
.scale(width)
.write(output, function (err) {
if (err) {
throw(err);
}
resolve();
});
}
catch (err) {
reject(err);
}
});
}
function convertFile(newPath) {
return new Promise(function (resolve, reject) {
try {
let convertedPath = newPath.replace(/\.[^/.]+$/, "") + ".png";
execFile("convert", [newPath, convertedPath]).then(function () {
fs.unlinkSync(newPath);
resolve({path: convertedPath});
});
}
catch (err) {
reject(err);
}
});
}
function addSql(data) {
return new Promise(function (resolve, reject) {
try {
current_import.sql.push(data);
current_import.done++;
updateProgressBar();
resolve();
}
catch (err) {
reject(err);
}
});
}
已编辑的代码(工作):
function createThumbnail(input, output, width) {
return new Promise(function (resolve, reject) {
gm(input)
.scale(width)
.write(output, function (err) {
if (err) {
return reject(err);
}
resolve();
});
});
}
function convertFile(newPath) {
let convertedPath = newPath.replace(/\.[^/.]+$/, "") + ".png";
return execFile("convert", [newPath, convertedPath]).then(function () {
fs.unlinkSync(newPath);
return convertedPath;
});
}
function addSql(data) {
current_import.sql.push(data);
current_import.done++;
updateProgressBar();
}
function queueFiles(files) {
return Promise.all(files.map(function (file) {
let original_filename = file.split("\\").pop();
let original_extension = original_filename.split(".").pop();
let hashed_name = crypto.createHmac('sha256', secret).update(original_filename).digest('hex') + "." + original_extension;
let new_path = data_folder + "/" + hashed_name;
return fs.copy(file, new_path).then(function () {
if (original_extension == "bmp") {
return convertFile(new_path)
.then(function (path) {
return {path: path, hash: path.split("/").pop()};
});
} else {
return {path: new_path, hash: hashed_name}
}
}).then(function (result) {
let outPath = thumb_folder + "/" + result.hash;
return createThumbnail(result.path, outPath, 500)
.then(function () {
return outPath;
});
}).then(function (thumb_path) {
return addSql(thumb_path);
});
}));
}
答案 0 :(得分:0)
首先,convertFiles
和queueFiles
不需要Promise构造函数
但问题是...... import_promises.copy_promises
是一系列承诺,import_promises.sql_promises
是一系列承诺,而import_promises.convert_promises
是一系列承诺......所以,你是在Promise数组的数组上执行Promise.all ... Promise.all期望一个承诺数组
chnage
Promise.all([import_promises.copy_promises, import_promises.convert_promises, import_promises.thumbnail_promises, import_promises.sql_promises]).then ...
到
Promise.all([].concat(import_promises.copy_promises, import_promises.convert_promises, import_promises.thumbnail_promises, import_promises.sql_promises).then ...
至于anipatterns,converFiles
可以简单地
function convertFile(newPath) {
let convertedPath = newPath.replace(/\.[^/.]+$/, "") + ".png";
return execFile("convert", [newPath, convertedPath]).then(function () {
fs.unlinkSync(newPath);
resolve({path: convertedPath});
});
}
addsql
甚至不是异步的,所以为什么它会返回一个承诺是一个谜 -
和queueFiles(没有深入研究那里的其他一些问题)可以
function queueFiles(files) {
for (file of files) {
let original_filename = file.split("\\").pop();
let original_extension = original_filename.split(".").pop();
let hashed_name = crypto.createHmac('sha256', secret).update(original_filename).digest('hex') + "." + original_extension;
let new_path = data_folder + "/" + hashed_name;
import_promises.copy_promises.push(fs.copy(file, new_path).then(function () {
if (original_extension == "bmp") {
import_promises.convert_promises.push(convertFile(new_path).then(function (result) {
import_promises.thumbnail_promises.push(createThumbnail(result.path, thumb_folder + "/" + result.path.split("/").pop(), 500).then(function () {
import_promises.sql_promises.push(addSql(result.data));
}));
}));
} else {
import_promises.thumbnail_promises.push(createThumbnail(new_path, thumb_folder + "/" + hashed_name, 500).then(function () {
import_promises.sql_promises.push(addSql(new_path));
}));
}
}));
}
return Promise.all([import_promises.copy_promises, import_promises.convert_promises, import_promises.thumbnail_promises, import_promises.sql_promises]);
}
在尝试理解流程之后,我已经想出了这个,我唯一不理解的部分是addSql函数,为什么它是一个承诺,
function convertFile(newPath) {
return execFile("convert", [newPath, convertedPath]).then(function () {
fs.unlinkSync(newPath);
return convertedPath;
});
}
function createThumbnail(input, output, width) {
return new Promise(function(resolve, reject) {
gm(input)
.scale(width)
.write(output, function (err) {
if (err) {
return reject(err);
}
resolve();
});
});
}
function addSql(data) {
current_import.sql.push(data);
current_import.done++;
updateProgressBar();
}
function queueFiles(files) {
return Promise.all(files.map(function(file) {
return fs.copy(file, new_path).then(function () {
if (original_extension == "bmp") {
return convertFile(new_path)
.then(function(path) {
return {path: path, hash: path.split("/").pop()};
});
} else {
return {path: new_path, hash: hashed_name}
}
}).then(function (result) {
return createThumbnail(result.path, thumb_folder + "/" + result.hash, 500)
.then(function() {
return result.path;
});
}).then(function(result) {
return addSql(result);
});
}));
}