Node中非常随机的行为,使用gm,buffers和promise

我最近把我的图像保存模块切换到gm (grahicsmagick),并开始使用缓冲区,而不是保存到磁盘。

我期望的输出是一个具有md5散列的数组,然后是原始图像和缩略图的path。 我用诺言,像这样。

 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,下一个几乎是相同的

 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的数组时,我得到了非常随机的哈希表,缩略图和原始path的混合,大概来自其他调用之前的函数。

当我不使用缓冲区或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 () { 

本节不正确:

 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 ,因此您获得的最终结果将取决于每个映像需要处理多长时间以及上传多长时间。

Console.log是asynchronous的; 所以它会以asynchronous顺序吐出东西,所以根据当前正在logging的内容,它很容易失序。

如果你真的必须通过控制台来追踪它, 使用console.error,因为它是同步的; 或使用一个简单的数组来推动一切; 然后在最后注销该数组。