Javascript 检查文件是否完全使用node.js编写
我需要一些帮助,帮助我如何用JavaScript处理以下任务: 我有一个应用程序,可以使用 用于图像处理和节点精灵生成器。所有这些都在node.js上下文中运行。我加载一些图像来Jimp,用图像制作一些东西,然后用nodejs文件模块将其写回我的文件系统。然后,我会将新创建的图像粘贴到节点精灵生成器。问题是,此时并非所有图像都被创建/写入。虽然创建spritesheet的代码在Jimp返回后立即运行,但我认为Jimp处理所有图像并返回承诺。结果是,创建spritesheet的代码得到执行,但堆栈没有完成 我尝试使用fs.stat()和类似于mtime的属性测试文件是否已写入Javascript 检查文件是否完全使用node.js编写,javascript,node.js,Javascript,Node.js,我需要一些帮助,帮助我如何用JavaScript处理以下任务: 我有一个应用程序,可以使用 用于图像处理和节点精灵生成器。所有这些都在node.js上下文中运行。我加载一些图像来Jimp,用图像制作一些东西,然后用nodejs文件模块将其写回我的文件系统。然后,我会将新创建的图像粘贴到节点精灵生成器。问题是,此时并非所有图像都被创建/写入。虽然创建spritesheet的代码在Jimp返回后立即运行,但我认为Jimp处理所有图像并返回承诺。结果是,创建spritesheet的代码得到执行,但堆栈
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,并且此时没有创建该文件时,我得到了一个错误 这里混合了同步和异步代码。我将尝试在评论中描述正在发生的事情: 首先,您的函数定义—您正在启动异步操作,而没有正确处理它们的完成
// 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()
是一个同步调用,您只需返回承诺并执行它:
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,因为它们变得无处不在
即使您的子调用是异步的,也有可能以同样的方式使用承诺,我只是没有准备好
否则,可以将回调传递到函数中:
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!');
});
});
希望这有帮助 如果你有一个承诺,你需要在第一个动作完成后用它来执行下一个动作。查看您的代码,或者至少是其中的一部分,在您正在转换任务的地方,以提供关于如何修复它的有用指导,这将是非常有帮助的。我也这么认为,因此我为jimp队列创建了一个then()函数,其中包含执行sprite sheet代码的fn调用。但我也有同样的问题。你需要给我们看你的代码。关于代码的问题必须包括问题中的相关代码。如果你给我们看代码,我们可能会在几分钟内帮上忙。它很有效!非常感谢你,杰森。PS:fn()函数实际上是一个rec()调用。这将调用函数本身,直到数组imgObj为空。但最重要的是,你帮我找到一个可行的解决方案。谢谢。好的,还有一条建议-递归调用的效率不如只在数组中循环,因此您的
rec()
函数应该只执行一个简单的循环,而不是调用自身并弹出元素。设置范围后,最终结果将是相同的。不管怎样,我很高兴这有帮助!