【问题标题】:How to close file handle with promises?如何用承诺关闭文件句柄?
【发布时间】:2018-12-27 21:56:34
【问题描述】:

我正在尝试使用 canvas 模块在 node.js 脚本中创建一个 PNG 文件。

我有一个文件 image.js 来处理图像创建:

const { createCanvas, loadImage } = require('canvas');
const fs = require('fs');

function generateImage(param1, param2) {
  const canvas = createCanvas(4096, 4096);
  const ctx = canvas.getContext('2d');
  // ...
  return new Promise(function (resolve, reject) {
    loadImage('base.png').then((image) => {
      ctx.drawImage(image, 40, 40, 200, 200);

      let out = fs.createWriteStream(__dirname + '/temp.png');
      let stream = canvas.pngStream();

      stream.on('data', function (chunk) {
        out.write(chunk);
      });

      stream.on('end', function () {
        console.log('saved png');
        out.close(); // i probably don't need both, but neither seems to work properly...
        out.end();
        resolve();
      });
    });
  });
}

module.exports = generateImage;

当我在此文件末尾附加 generateImage('a', 'b'); 然后单独运行它 (node image.js) 时,它会按预期工作并生成我的图像。但是,当我尝试从不同的文件(在同一文件夹中)调用它时,文件句柄似乎没有关闭,并且在脚本运行时磁盘上的图像是一个空文件。

main.js(简体):

const generateImage = require('./image');
const fs = require('fs');

async function main() {
    var stats = fs.statSync("temp.png");
    console.log(stats["size"]); // output: 0, expected: > 0
}

generateImage("text", "text").then(() => main());

我是 node.js 的新手,所以我很可能遗漏了一些明显的东西。

【问题讨论】:

  • 这是完整的代码吗?我想你可能在拳头 sn-p 中错过了steam.pipe(out)
  • 与您的问题无关,但请避免使用Promise constructor antipattern!将loadImage('base.png') 调用放在new Promise 之外,然后用then 链接它们。
  • out.endappears to be asynchronous。在解决 promise 之前,您需要等待 out 流上的 closefinish 事件。
  • @Bergi 谢谢,这就是问题所在!我的事件监听器现在如下所示:stream.on('end', () => out.end());out.on('close', () => resolve());。不过,我无法弄清楚如何改进我的代码以避免提到的反模式。如果您可以用更优雅的解决方案发布答案​​,我很乐意接受!
  • @martonbognar 基本上只是将return new Promise(function (resolve, reject) { loadImage('base.png').then((image) => { 换成return loadImage('base.png').then((image) => new Promise(function (resolve, reject) {。或者,如果你想使用async/await,那么它就是const image = await loadImage('base.png'); return new Promise(function (resolve, reject) {…});

标签: javascript node.js canvas promise async-await


【解决方案1】:

根据Bergi 的建议,我需要为out 流的close 事件添加另一个事件侦听器,并且只有在触发后才调用resolve()。我还链接了承诺,而不是像问题中那样嵌入它们。

function generateImage(param1, param2) {
  const canvas = createCanvas(4096, 4096);
  const ctx = canvas.getContext('2d');
  // ...
  return loadImage('base.png').then((image) => new Promise(function (resolve, reject) {
    ctx.drawImage(image, 40, 40, 200, 200);

    let out = fs.createWriteStream(__dirname + '/temp.png');
    let stream = canvas.pngStream();

    stream.on('data', (chunk) => out.write(chunk));
    stream.on('end', () => out.end());
    out.on('close', () => resolve());  // this was missing
  }));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    • 2011-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-24
    相关资源
    最近更新 更多