简体   繁体   中英

NodeJS/gm: Promises with asynchronous calls

I'm using gm to manipulate some images in my nodeJS application. This is how my function looks like.

As you can see there is a switch for some manipulation (in this example: rotation). gmStream is created and after the switch .stream() and pipe() will be used. So far everything is fine.

But for the switch case resize , I need to know the dimensions of the image, which I do get via size() . But this is an asynchronous call. With this gmStream isn't used for the stream() shown below the switch. But there will be done some more DB stuff in this stream() , so I need to use the same thing...

function manipulate (method, param) {
  return new Promise(function (resolve, reject) {

    // Configure GridFS (gridfs-stream)
    const gfs = Grid(
      MongoInternals.defaultRemoteCollectionDriver().mongo.db,
      MongoInternals.NpmModule
    )

    switch (method) {
      case 'rotate':
        gmStream = gm(readStream)
          .rotate('#ffffff', param.rotate)
        break

      // ... some more cases ...

      case 'resize':
        gmStream = gm(readStream)
          .size(function (err, size) {
            if (!err && size.width >= 1000 && size.height >= 1000) {
              gmStream.resize('1000').stream().pipe(writeStream) // <-- should use the stream call below, as there has to be done some DB manipulation...
            }
          })
        break
    }

    // resize case should also use this part...
    gmStream
      .stream(function (err, stdout, stderr) {
        gfs.findOne({ _id: sourceId }, function (err, file) {
          const writeStream = gfs.createWriteStream({
            metadata: { }
          })

          writeStream.on('close',
            function (newFile) {
              resolve(newFile)
            }
          )

          stdout.pipe(writeStream)
        })
      })
  })
}

You may want to chain Promises together to accomplish what you're after. If you break apart the logic in your switch case into Promise-returning functions, you might be able to get something like the following to work (disclaimer: I've never used gm and I'm not familiar with its API).

function rotate (readStream, rotate) {
  return new Promise(function (resolve, reject) {
    resolve(gm(readStream).rotate('#ffffff', param.rotate))
  })
}


function resize (readStream, writeStream) {
  return new Promise(function (resolve, reject) {
    var gmStream = gm(readStream)

    gmStream.size(function (err, size) {
      if (err) {
        return reject(err)
      }

      if (size.width >= 1000 && size.height >= 1000) {
        gmStream.resize('1000').stream().pipe(writeStream)
        resolve(gmStream)
      }
    })
  })
}


function handleManipulation (args) {
  return new Promise(function (resolve, reject) {
    // This will be a Promise for the base gmStream object to work with
    var gmStream;

    // Not sure where this comes from, so here's a placeholder
    var readStream = ...;

    // You were doing this for every case, so I don't think putting it here
    // will cause you any grief, but it's a resource to clean up if the
    // Promise gets rejected, so keep that in mind
    const writeStream = gfs.createWriteStream({
      metadata: { }
    })

    // Figure out which method to create a Promise'd object for
    switch (args.method) {
      case 'rotate':
        gmStream = rotate(readStream, ...) // I'm not sure what the value of
                                           // the `rotate` argument should be
        break
      case 'resize':
        gmStream = resize(readStream, writeStream)
        break
    }

    // We wait for the gmStream Promise to resolve before proceeding.
    gmSteam.then(function (stream) {
      stream.stream(function (err, stdout, stderr) {
        if (err) {
          return reject(err)
        }

        gfs.findOne({ _id: sourceId }, function (err, file) {
          if (err) {
            return reject(err)
          }

          writeStream.on('close',
            function (newFile) {
              resolve(newFile)
            }
          )

          stdout.pipe(writeStream)
        })
      })
    })
  })
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM