Javascript JS:递归调用承诺函数

Javascript JS:递归调用承诺函数,javascript,node.js,Javascript,Node.js,我正在制作一个node.js应用程序,可以为图像创建缩略图。为了避免在生成缩略图时冻结应用程序,我决定使用异步方法创建缩略图。但是,根据图像的不同,可能需要多个缩略图大小 var thumbnailSizes = [100]; if (image.type == 'coolImage') thumbnailSizes.push(500); generateThumbnails(image.filename, thumbnailSizes).then(function() { // Do

我正在制作一个node.js应用程序,可以为图像创建缩略图。为了避免在生成缩略图时冻结应用程序,我决定使用异步方法创建缩略图。但是,根据图像的不同,可能需要多个缩略图大小

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函数,一直跳到最后,从未解析。我如何才能做到这一点?

似乎您正在用另一个承诺来解决您的承诺,这可能会导致承诺链断裂,您可以尝试更改:

resolve(generateThumbnails(文件名,缩略图大小。拼接(0,1))

为了

返回generateThumbnails(文件名、缩略图大小.拼接(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
        })
}

您只在回调中条件的
else
块中调用
resolve
,而不是在
if
块中调用。解析递归调用返回的承诺不会对外部调用返回的承诺产生任何影响。此外,如果出现错误,您决不会拒绝承诺

无论如何,您应该避免调用,这样您根本不需要任何
resolve
调用,只需从
返回
,然后
回调链承诺:

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);
});

我还修复了您的递归-基本情况应该是空数组。

我认为这里不需要递归

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
    });
  }
}
它与调用函数中的wait
循环一起使用:

for await(const thumbnail of generateThumbnails(file, sizes) {
  // handle single size
}

另外,我不会使用
.substring()
来进行路径操作,我确信有一个或七个函数可以帮助您可靠地从路径中提取感兴趣的部分。

而不是
解析(generateThumbnails(filename,thumbnailsize.splice(0,1))尝试只返回承诺
返回generateThumbnails(文件名,缩略图大小.splice(0,1))
这实际上是我在使用resolve()之前尝试的。两者都给出了相同的结果。同样
返回thumb({…})
:)如果我返回thumb,我会得到控制台输入
开始>长度=2>结束
,并且没有生成缩略图。避免!我发现错误
await仅在异步函数中有效
。我不确定是否可以按照您建议的方式使用缩略图函数()。请看一下我编写的代码的第一部分,您需要将函数定义为async://your function definition//async()=>{我不知道该告诉您什么,我完全不知所措。此函数不会触发
thumb()
一次,基于控制台输出,它确实应该是。我还承诺了
generateThumbnails()
,因为“保存缩略图的酷东西”部分需要在缩略图创建之后发生。哎呀,我错过了添加第二个基本
return
关键字。现在应该可以工作了。
thumb()
仍然没有被调用。控制台中没有错误,也没有解决方案。就好像这个函数根本不存在似的。所以你得到了
开始
日志,
长度=…
日志的大小为1或更大,然后什么都没有?这肯定很奇怪。这就是正在发生的事情。而这会生成我的缩略图按照我的要求,它还会在创建主进程时冻结主进程。此外,我应该如何捕获
Promise.all
Promise.all()
将在第一个拒绝的承诺时拒绝,因此您可以在其周围添加
try/catch
块(因为您使用的是异步函数)如果你想要所有的错误,你可以做更多的欺骗。至于阻塞主线程,恐怕这是<代码>拇指<代码>函数的错误,并且这里没有什么可以做的。考虑使用新的<代码> WorksOrthys< /Cult>模块切换到一个库来做CPU接口。在不阻塞主线程的情况下启动工作。