【问题标题】:Check if file is completely written with node.js检查文件是否完全用 node.js 编写
【发布时间】:2016-10-13 15:40:33
【问题描述】:

我需要一些帮助,我可以在 JavaScript 中处理以下任务: 我有一个应用程序,使用 Jimp 用于图像处理和节点精灵生成器。这一切都在 node.js 上下文中运行。我将一些图像加载到 Jimp,用图像制作一些东西,然后使用 nodejs 文件模块将其写回我的文件系统。然后我会将新创建的图像粘贴到 node-sprite-generator。问题是,此时并非所有图像都被创建/写入。虽然创建 spritesheet 的代码在 Jimp 返回后立即运行,但我认为 Jimp 会处理所有图像并返回一个承诺。结果是,创建 spritesheet 的代码被执行但堆栈没有完成。

我尝试使用 fs.stat() 和属性 mtime 来测试文件是否已写入

 if (stat.mtime.getTime() === prev.mtime.getTime())

但是,当此时未创建文件时,可能会发生错误。另外:当图像的路径当前不可用时,我需要一种方法来检查图像是否完全通过处理写入。

function resize(img) {
    Jimp.read(img.path).then(function (err, file) {
        if (err) throw err;
        file.resize(200, 200)
            .quality(70)
            .write(newPath); //newPath for simplicity
    });
}


function rec(imgObjArray) {
    if(_.isEmpty(imgObjArray)) return;  
    resize(imgObjArray.pop());
//correct mistake in function call from fn() to rec()
    rec(imgObjArray);
}

rec(imgObjArray); //imgObjArray === [img,img,img....]

//nsg() does not work because not all images are written at this time
     nsg({
            src: [
                'out/images/desktop/*.jpg'
            ],
            spritePath: 'out/images/desktop/sprite.jpg',,
            compositor: 'jimp'
        }, function (err) {
            console.log('Sprite generated!');
        })

我认为首先我必须检查图像是否存在于给定路径中,然后检查是否写入完成。但是,当我使用 fs.access(path[, mode], callback) 进行 fn 并且此时未创建文件时,出现错误。

【问题讨论】:

  • 如果你有一个承诺,你需要在第一个动作完成后使用它来执行下一个动作。查看您的代码或至少其中一部分您正在转换任务的代码会很有帮助,以提供有关如何修复它的任何有用指导。
  • 我也是这么想的,所以我为 jimp 队列创建了一个 then() 函数,其中包含 fn-call 以执行 sprite-sheet 代码。但我遇到了同样的问题。
  • 您需要向我们展示您的代码。有关代码的问题必须在您的问题中包含相关代码。如果您向我们展示代码,我们可能会在几分钟内提供帮助。

标签: javascript node.js


【解决方案1】:

您在这里混合了同步和异步代码。我将尝试描述 cmets 中发生的事情:

首先,您的函数定义 - 您在未正确处理完成的情况下触发异步操作

// I've re-spaced the code slightly and removed your comments so mine stand out
function resize(img) {
    Jimp.read(img.path).then(function (err, file) {
        // this code only executes after the file is done reading, but this
        // is an asynchronous action - it doesn't hold up execution
        if (err) throw err;
        file.resize(200, 200).quality(70).write(newPath);
        // .write() is presumably *also* an asynchronous action - if you want
        // something to happen only *after* it's been written, it needs to be in
        // a callback or promise on the write method
    });

    // I added this explicitly - after you *start* your Jimp.read, you *immediately*
    // return from this function, *before* the read is completed.  If you want
    // something to happen only *after* your read and write, you either need to
    // return the promise so you can act on it, or put the further actions in a callback
    return undefined;
}

function rec(imgObjArray) {
    if(_.isEmpty(imgObjArray)) return; 
    // resize() runs and returns *before* the file is read, resized, and written
    resize(imgObjArray.pop());
    // I don't know what fn() is, it's not defined here - presumably it's not important
    fn(imgObjArray);
}

...然后,您的程序调用:

// this fires off and completes immediately, having initiated the asynchronous methods
rec(imgObjArray);

// you call this on the assumption that all of your code above has completed, but since
// it's asynchronous, that's not true, you get here with *none* of your images completed
nsg({
    src: [
        'out/images/desktop/*.jpg'
    ],
    spritePath: 'out/images/desktop/sprite.jpg',
    compositor: 'jimp'
}, function (err) {
    console.log('Sprite generated!');
});

你有两个选择:

如果file.write() 是同步调用,你可以只返回promise 并执行它:

function resize(img) {
    // by *returning* this call, we're actually returning the promise, we can act on
    // in the future
    return Jimp.read(img.path).then(function (err, file) {
        if (err) throw err;
        file.resize(200, 200).quality(70).write(newPath);
    });
}

function rec(imgObjArray) {
    if(_.isEmpty(imgObjArray)) return; 
    // the result of resize is now a promise
    return resize(imgObjArray.pop()).then(function(err) {;
        // again, assuming `fn()` is synchronous...
        fn(imgObjArray);
    });
}

// now the result of *this* call is a promise, which you can use to control
// the timing of your next call
rec(imgObjArray).then(function(err) {
    // now this will only run after all of the previous calls have executed
    nsg({
        src: [
            'out/images/desktop/*.jpg'
        ],
        spritePath: 'out/images/desktop/sprite.jpg',
        compositor: 'jimp'
    }, function (err) {
        console.log('Sprite generated!');
    });
});

... 如果 promise 语法不正确,我深表歉意,自从 node 变得无处不在以来,我没有积极使用过。

即使您的子调用是异步的,也有可能以相同的方式使用 Promise,我只是没有准备好。

否则,您可以将回调传递给您的函数:

function resize(img, cb) {
    // ... you get the idea...
        file.resize(200, 300).quality(70).write(newPath, cb);
}

function rec(imgObjArray, cb) {
    // ... you get the idea...
    resize(imgObjArray.pop(), cb);
}

rec(imgObjArray, function(err, response) {
    nsg({
        src: [
            'out/images/desktop/*.jpg'
        ],
        spritePath: 'out/images/desktop/sprite.jpg',
        compositor: 'jimp'
    }, function (err) {
        console.log('Sprite generated!');
    });
});

希望这会有所帮助!

【讨论】:

  • 它工作!非常感谢@Jason。 PS: fn() 函数实际上是一个 rec() 调用。这将调用函数本身,直到数组 imgObj 为空。但最重要的是,你帮我找到一个可行的解决方案。谢谢。
  • 好的,所以还有一条建议——递归调用的效率低于循环数组,所以你的rec() 函数应该只做一个简单的循环,而不是调用自身并弹出元素。设置范围后,最终结果将是相同的。不管怎样,我很高兴这有帮助!
猜你喜欢
  • 2012-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-29
  • 2013-05-18
  • 1970-01-01
相关资源
最近更新 更多