【问题标题】:Promise resolving too early承诺过早解决
【发布时间】:2021-04-23 19:21:02
【问题描述】:

我遇到了一个问题,我的 Promise.all 解决得太早了。对于测试,我想 console.log 从 promise 映射中推送的数组的长度,但遗憾的是它返回 0。我敢肯定这很简单......

fromPath(job.data.path, { density: 100, format: "png" }).bulk(-1, true).then(output => {
  Promise.all(output.map(page => 
    jimp.read(Buffer.from(page.base64, 'base64')).then(img => 
      {
        img.invert().getBase64Async(jimp.AUTO).then(data => imageArray.push(data.replace('data:image/png;base64,', ''))).catch(err => console.log(err))
      }
      ).catch(err => console.log(err))
      )).catch(err => console.log(err))
}
  // This returns early
).then(console.log(imageArray.length)).then(done()).catch(err => console.log(err));

任何帮助将不胜感激。

【问题讨论】:

  • 您的then 回调没有返回任何内容。你应该返回 Promise.all(),你应该返回 img.invert().....
  • 这是一个错字。你忘记在它所在的.then处理程序中返回来自img.invert().getBase64Async的承诺,所以来自.then的承诺不会等待来自getBase64Async的承诺。 (还有上面的 Promise.all,直接调用console.log 并将其返回值传递给.then,然后...)

标签: javascript node.js promise


【解决方案1】:

那里有很多问题。主要分为以下几类:

  • 不从履行处理程序返回承诺链的结果,这意味着履行处理程序所在的链不会链接到您在其中创建的承诺链
  • 调用函数并将其返回值传递给then,而不是将函数传递给then

在该代码的最小更改中查看内联 cmets:

fromPath(job.data.path, { density: 100, format: "png" }).bulk(-1, true)
.then(output => {
    // Return the result of `Promise.all`
    return Promise.all(
        output.map(
            page => jimp.read(Buffer.from(page.base64, 'base64'))
                .then(img => {
                    // Return the ersult of this promise chain
                    return img.invert().getBase64Async(jimp.AUTO)
                    .then(data => imageArray.push(data.replace('data:image/png;base64,', '')))
                    // This error handler does nothing useful, since we now return
                    // the promise chain
                    // .catch(err => console.log(err))
                })
                // Recommend **not** handling errors at this level, but using
                // `Promise.allSettled` instead
                .catch(err => console.log(err))
        )
    )
    // This will only be reached if a *synchronous* error occurs calling (for instance)
    // `getBase64Async`, since you've already caught errors above
    .catch(err => console.log(err))
})
// Use a function here, don't call `console.log` directly
.then(() => console.log(imageArray.length))
//    ^^^^^^
// Pass `done` directly to `then`, don't call it and pass its return value
// (e.g., remove the `()`)
.then(done) // Or `.then(() => done)` if you want `done` called with no arguments
.catch(err => console.log(err));

FWIW,不过,如果我不得不不使用 async 函数,我可能会这样做:

fromPath(job.data.path, { density: 100, format: "png" }).bulk(-1, true)
.then(output => Promise.allSettled(
    output.map(
        page => jimp.read(Buffer.from(page.base64, 'base64'))
            .then(img => img.invert().getBase64Async(jimp.AUTO))
            .then(data => {
                imageArray.push(data.replace('data:image/png;base64,', ''));
            })
    )
))
.then(results => {
    // Show errors
    const errors = results.filter(({status}) => status === "rejected");
    for (const {reason} of errors) {
        console.error(reason);
    }
    // Done
    done();
});

【讨论】:

  • 您好 TJ,非常感谢您的帮助和详细的评论!你是个明星。 RE:内联格式化和阅读 Promise,我的朋友,所有工作都在进行中。再次感谢。
  • @TobyBoulton - :-) 很高兴有帮助。我添加了可能有用的第二个版本。编码愉快!
猜你喜欢
  • 2019-06-15
  • 2016-09-13
  • 2017-12-13
  • 2014-06-16
  • 2018-03-27
  • 2015-06-24
  • 2019-09-29
  • 1970-01-01
  • 2020-03-16
相关资源
最近更新 更多