我正在制作一个可以为图像创建缩略图的node.js应用程序。为了避免在生成缩略图时冻结应用程序,我决定使用异步library来创建缩略图。但是,根据图像,可能需要多个缩略图大小。
var thumbnailSizes = [100];
if (image.type == 'coolImage') thumbnailSizes.push(500);
generateThumbnails(image.filename, thumbnailSizes).then(function() {
// Do cool things with the saved thumbnails (This is never reached)
});
function generateThumbnails(filename, thumbnailSizes) {
return new Promise(resolve => {
var path = filename.substring(0, filename.lastIndexOf('\\'));
console.log('start');
console.log('length = ' + thumbnailSizes.length);
thumb({
prefix: thumbnailSizes[0] + '_';
source: filename,
destination: path,
width: thumbnailSizes[0]
}).then(function () {
if (thumbnailSizes.length > 1) {
console.log('next');
generateThumbnails(filename, thumbnailSizes.splice(0, 1));
} else {
console.log('finished');
resolve('true');
}
}).catch(function (e) {
console.log('error');
});
console.log('end');
});
}
此代码成功创建了第一个缩略图,但没有创建第二个。代码停止运行后,这就是我的控制台的样子。
> Console Output
start
length = 2
end
next
start
length = 1
end
该代码第二次成功调用generateThumbnails()
,但是没有再次调用thumb函数,一直跳到结尾并且从未解析。我该如何工作?
答案 0 :(得分:2)
我认为这里不需要递归。
async function generateThumbnails(filename, thumbnailSizes) {
var path = filename.substring(0, filename.lastIndexOf('\\'));
return await Promise.all(thumbnailSizes.map(size => thumb({
prefix: `${size}_`,
source: filename,
destination: path,
width: size
})));
}
或者如果您需要一张一张地创建缩略图:
async function* generateThumbnails(filename, thumbnailSizes) {
var path = filename.substring(0, filename.lastIndexOf('\\'));
for(const size of thumbnailSizes) {
yield await thumb({
prefix: `${size}_`,
source: filename,
destination: path,
width: size
});
}
}
哪些可以在调用函数中与for await
循环一起使用:
for await(const thumbnail of generateThumbnails(file, sizes) {
// handle single size
}
此外,我不会使用.substring()
进行路径操作,我确定Node path
module具有一个或七个功能可以帮助您可靠地从路径中提取有趣的部分。
答案 1 :(得分:0)
您似乎正在用另一个承诺解决您的承诺,这可能会导致承诺链中断,您可以尝试更改:
resolve(generateThumbnails(filename, thumbnailSizes.splice(0, 1)));
为
return generateThumbnails(filename, thumbnailSizes.splice(0, 1))
但是我的建议是(如果您使用的是最新的ES版本)使用async / await,那么您不需要递归调用,并且您的代码将更具可读性:
// your function definition
//async () => {
var thumbnailSizes = [100];
if (image.type == 'coolImage') thumbnailSizes.push(500);
for(const size of thumbnailSizes) { // do not use a foreach
const thumbnail = await generateThumbnail(image.fineName, size);
// Do more fun stuff with your thumbnail
}
});
function generateThumbnail(filename, size) {
var path = filename.substring(0, filename.lastIndexOf('\\'));
return thumb({
prefix: size + '_';
source: filename,
destination: path,
width: size
})
}
答案 2 :(得分:0)
您仅在回调条件中的resolve
块中调用else
,而不在if
块中调用。解决递归调用返回的诺言对外部调用返回的诺言没有任何影响。同样,如果发生错误,您也永远不会reject
保证。
无论如何,您应该避免使用Promise
constructor antipattern,这样就根本不需要任何resolve
调用,而只需从return
回调中的then
到链式承诺即可:
function generateThumbnails(filename, thumbnailSizes) {
console.log('length = ' + thumbnailSizes.length);
if (thumbnailSizes.length == 0) {
console.log('finished');
return 'true'; // are you sure?
} else {
var path = filename.substring(0, filename.lastIndexOf('\\'));
return thumb({
// ^^^^^^
prefix: thumbnailSizes[0] + '_';
source: filename,
destination: path,
width: thumbnailSizes[0]
}).then(function () {
console.log('next');
return generateThumbnails(filename, thumbnailSizes.slice(1));
// ^^^^^^
})
}
}
…
var thumbnailSizes = [100];
if (image.type == 'coolImage') thumbnailSizes.push(500);
console.log('start');
generateThumbnails(image.filename, thumbnailSizes).then(function() {
console.log('end');
// Do cool things with the saved thumbnails (This is never reached)
}, function(err) {
console.log('error', err);
});
我也修复了您的递归-基本情况应该是空数组。