【发布时间】:2017-01-29 20:59:38
【问题描述】:
我正在尝试实现多个异步调用,并且只有在全部完成后才继续。
过程是这样的,我需要按以下顺序完成: 获取文件路径列表, 将它们复制到新的目的地, 转换位图, 创建缩略图, 将信息添加到数组中以批量插入数据库
为此,我使用了 Promise 数组和 Promise.all() 方法。此方法触发得太早,因为它在承诺数组尚未(完全)填充时执行。 如果我在 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);
});
}));
}
【问题讨论】:
-
像这样使用
new Promise通常是antipattern
标签: javascript node.js ecmascript-6 promise