Node 中具有 gm、缓冲区和承诺的非常随机的行为
Very random behaviour in Node with gm, buffers and promises
我最近将我的图像保存模块切换到 gm
(grahicsmagick) 并开始使用缓冲区而不是保存到磁盘。
我期望的输出是一个带有 md5 散列的数组,然后是原始图像和缩略图的路径。我像这样使用承诺。
saveOrig( imageUrl )
.then( saveThumb )
.then( function( image ) {
var returnArray = [ image.hash, image.orig, image.thumb ]
console.log( returnArray )
resolve( returnArray )
})
.catch( function( error ) {
reject( new Error( error.message ) )
})
这里是第一个函数,下一个几乎一模一样
function saveOrig ( imageUrl ) {
return Q.Promise( function ( resolve, reject, notify ) {
var image = {
extension: path.extname( imageUrl )
}
gm( request( imageUrl ) )
.format( function( err, value ) {
if ( err ) return reject ( new Error ( err ) )
image.type = value
})
.stream( image.type, function ( err, stdout, stderr ) {
if ( err ) return reject( new Error( err ) )
var bufs = []
stdout.on( 'data', function ( d ) {
bufs.push( d )
})
stdout.on( 'end', function () {
var buf = Buffer.concat( bufs )
image.hash = crypto.createHash( 'md5' ).update( buf ).digest( 'hex' )
console.log ( image.hash )
uploader = s3Client.putBuffer( buf, type + "/" + image.hash + "-orig" + image.extension, {
'Content-Length': buf.length,
'Content-Type': 'image/jpeg'
}, function ( err, result ) {
if ( err ) return reject( new Error( err ) )
if ( result.statusCode == 200 ) {
image.orig = uploader.url
resolve( image )
}
})
})
})
})
}
同样,这是我希望看到的,
[ '820f841a0a7cdc854b70f8b534dc7705',
'https://my-amazon-bucket.s3.amazonaws.com/read/820f841a0a7cdc854b70f8b534dc7705-orig.jpeg',
'https://my-amazon-bucket.s3.amazonaws.com/read/820f841a0a7cdc854b70f8b534dc7705-thumb.jpeg' ]
这就是我只处理一张图像时发生的情况。但是,当我使用 Q.all
调用此映射到数组的函数时,我得到了哈希、缩略图和原始路径的极其随机的看似混合,可能来自对它之前的函数的其他调用。
我以前没有使用缓冲区或 gm
时没有这种行为。这是什么原因?
编辑:这是我调用上述 saveImage
函数的方式。当我将项目保存到磁盘,然后使用 easy-image 模块处理它们时,这似乎工作正常。
images = window.document.getElementsByTagName( 'img' )
imageMapFunction = Array.prototype.map.call( images, function ( each, index ) {
return Q.promise( function ( resolve, reject, notify ) {
saveImage( req.body.type, each.src )
.spread( function ( imageHash, imageOriginalPath, imageThumbPath ) {
article.images.push({
image: imageOriginalPath,
imageHash: imageHash,
imageThumb: imageThumbPath
})
each.src = imageOriginalPath
resolve()
})
})
})
Q.all( imageMapFunction )
.then( function () {
Console.log 是异步的;所以它会以异步顺序吐出东西,因此根据当前记录的内容,它很容易乱序。
如果你真的必须通过控制台跟踪它;使用 console.error 因为它是同步的;或使用一个简单的数组将所有内容推入;然后在最后注销该数组。
此部分不正确:
uploader = s3Client.putBuffer( buf, type + "/" + image.hash + "-orig" + image.extension, {
'Content-Length': buf.length,
'Content-Type': 'image/jpeg'
}, function ( err, result ) {
if ( err ) return reject( new Error( err ) )
if ( result.statusCode == 200 ) {
image.orig = uploader.url
resolve( image )
}
});
您需要 var
作为 var uploader
。
就像现在一样,如果你多次调用你的函数,你每次都会覆盖一个全局 uploader
,所以你得到的最终结果将取决于每张图像的处理时间和处理方式他们需要很长时间才能上传。
我最近将我的图像保存模块切换到 gm
(grahicsmagick) 并开始使用缓冲区而不是保存到磁盘。
我期望的输出是一个带有 md5 散列的数组,然后是原始图像和缩略图的路径。我像这样使用承诺。
saveOrig( imageUrl )
.then( saveThumb )
.then( function( image ) {
var returnArray = [ image.hash, image.orig, image.thumb ]
console.log( returnArray )
resolve( returnArray )
})
.catch( function( error ) {
reject( new Error( error.message ) )
})
这里是第一个函数,下一个几乎一模一样
function saveOrig ( imageUrl ) {
return Q.Promise( function ( resolve, reject, notify ) {
var image = {
extension: path.extname( imageUrl )
}
gm( request( imageUrl ) )
.format( function( err, value ) {
if ( err ) return reject ( new Error ( err ) )
image.type = value
})
.stream( image.type, function ( err, stdout, stderr ) {
if ( err ) return reject( new Error( err ) )
var bufs = []
stdout.on( 'data', function ( d ) {
bufs.push( d )
})
stdout.on( 'end', function () {
var buf = Buffer.concat( bufs )
image.hash = crypto.createHash( 'md5' ).update( buf ).digest( 'hex' )
console.log ( image.hash )
uploader = s3Client.putBuffer( buf, type + "/" + image.hash + "-orig" + image.extension, {
'Content-Length': buf.length,
'Content-Type': 'image/jpeg'
}, function ( err, result ) {
if ( err ) return reject( new Error( err ) )
if ( result.statusCode == 200 ) {
image.orig = uploader.url
resolve( image )
}
})
})
})
})
}
同样,这是我希望看到的,
[ '820f841a0a7cdc854b70f8b534dc7705',
'https://my-amazon-bucket.s3.amazonaws.com/read/820f841a0a7cdc854b70f8b534dc7705-orig.jpeg',
'https://my-amazon-bucket.s3.amazonaws.com/read/820f841a0a7cdc854b70f8b534dc7705-thumb.jpeg' ]
这就是我只处理一张图像时发生的情况。但是,当我使用 Q.all
调用此映射到数组的函数时,我得到了哈希、缩略图和原始路径的极其随机的看似混合,可能来自对它之前的函数的其他调用。
我以前没有使用缓冲区或 gm
时没有这种行为。这是什么原因?
编辑:这是我调用上述 saveImage
函数的方式。当我将项目保存到磁盘,然后使用 easy-image 模块处理它们时,这似乎工作正常。
images = window.document.getElementsByTagName( 'img' )
imageMapFunction = Array.prototype.map.call( images, function ( each, index ) {
return Q.promise( function ( resolve, reject, notify ) {
saveImage( req.body.type, each.src )
.spread( function ( imageHash, imageOriginalPath, imageThumbPath ) {
article.images.push({
image: imageOriginalPath,
imageHash: imageHash,
imageThumb: imageThumbPath
})
each.src = imageOriginalPath
resolve()
})
})
})
Q.all( imageMapFunction )
.then( function () {
Console.log 是异步的;所以它会以异步顺序吐出东西,因此根据当前记录的内容,它很容易乱序。
如果你真的必须通过控制台跟踪它;使用 console.error 因为它是同步的;或使用一个简单的数组将所有内容推入;然后在最后注销该数组。
此部分不正确:
uploader = s3Client.putBuffer( buf, type + "/" + image.hash + "-orig" + image.extension, {
'Content-Length': buf.length,
'Content-Type': 'image/jpeg'
}, function ( err, result ) {
if ( err ) return reject( new Error( err ) )
if ( result.statusCode == 200 ) {
image.orig = uploader.url
resolve( image )
}
});
您需要 var
作为 var uploader
。
就像现在一样,如果你多次调用你的函数,你每次都会覆盖一个全局 uploader
,所以你得到的最终结果将取决于每张图像的处理时间和处理方式他们需要很长时间才能上传。