node.js使用bluebird

时间:2015-11-14 09:44:49

标签: node.js promise bluebird

我最近开始学习用node.js编写应用程序,所有东西的异步性质给我带来了一些麻烦。

我正在尝试编写一个遍历对象数组的脚本(例如下面的例子)。每个对象都包含一些我要下载的文件(plist,png)的URL。下载后,我想从一个数据中获取一些数据,然后根据该数据裁剪另一个数据。

当我创建一个对象并通过promise链(我在下面提供的示例)中传递它时,我有这个工作。我遇到的问题是当我尝试使用Promise.eachPromise.allPromise.mapSeries时。当我使用它们时,很明显(按照我的console.log语句的顺序)它们都是立即运行而不是一次运行。

这是我正在工作的一个例子。对不起,这么久了,我试着保持它整洁,以便它是可以理解的。

// ---------------------------------------------------------------------------

var Promise = require("bluebird"),
  fs = Promise.promisifyAll(require("fs")),
  gm = Promise.promisifyAll(require("gm")),
  plist = require("plist"),
  request = require("request-promise")


// ---------------------------------------------------------------------------
// Test Data
// This is what I'd like to replace with an array which would contain a few hundred of these

var card = {
  slug: "neutral_zurael",
  plist: "https://assets-counterplaygames.netdna-ssl.com/production/resources/units/neutral_zurael.plist",
  sprite: "https://assets-counterplaygames.netdna-ssl.com/production/resources/units/neutral_zurael.png"
}


// ---------------------------------------------------------------------------

var getXML = function() {
  console.log("getXML")
  return request({url: card.plist, gzip: true})
}

var writeXML = function(file){
  console.log("writeXML")
  return fs.writeFile("./lib/card.plist", file)
}

var getSprite = function() {
  console.log("getSprite")
  return request({url: card.sprite, gzip: true, encoding: "binary"})
}

var writeSprite = function(file) {
  console.log("writeSprite")
  return fs.writeFile("./lib/card.png", file, "binary")
}

var parseXML = function() {
  console.log("parseXML")
  var obj = plist.parse(fs.readFileSync("./lib/card.plist", "utf8"))
  var framename = card.slug + "_idle_000.png"
  var frame = obj.frames[framename].frame
  var values = frame.replace(/[{}]/g, "").split(",")
  var data = { x: values[0], y: values[1], width: values[2], height: values[3] }
  return data
}

// Not returning a promise due to chained methods
var cropImage = function(data){
  console.log("cropImage")
  return gm("./lib/card.png")
    .crop(data.width, data.height, data.x, data.y)
    .write("./lib/avatar.png", function(error){
      if (!error) {
        fs.unlink("./lib/card.plist")
        fs.unlink("./lib/card.png")
        console.log("Image Created")
      }
    })
}


// ---------------------------------------------------------------------------

getXML()
  .then(writeXML)
  .then(getSprite)
  .then(writeSprite)
  .then(parseXML)
  .then(cropImage)
  .catch(function(error){
    console.log(error)
  })
  .done()

这实际上是按原样运作的。我正在寻找一些帮助,将其转换为适用于对象数组的东西。我需要一种方法来传递它们并让它顺序运行(或者如果它们都将立即运行则更具弹性)。

任何建议都会有所帮助,因为我是新手,但却完全努力让它发挥作用。谢谢!

1 个答案:

答案 0 :(得分:1)

您正在使用的request-promise模块会将正常的request调用转换为使用promises而不是回调。但是,蓝鸟的Promise.promisifyAll()的工作方式不同。它保留了fs.writeFile()等方法的正常回调版本,就像它们一样。

相反,它添加了返回promise的那些函数的新版本。默认情况下,新版本与原始版本具有相同的名称,并添加了" Async"最后,fs.writeFileAsync()返回一个承诺。

因此,您必须使用适当的方法名称才能使用promises:

所以改变这些:

var writeXML = function(file){
  console.log("writeXML")
  return fs.writeFile("./lib/card.plist", file)
}

var writeSprite = function(file) {
  console.log("writeSprite")
  return fs.writeFile("./lib/card.png", file, "binary")
}

到这些:

var writeXML = function(file){
  console.log("writeXML")
  return fs.writeFileAsync("./lib/card.plist", file)
}

var writeSprite = function(file) {
  console.log("writeSprite")
  return fs.writeFileAsync("./lib/card.png", file, "binary")
}

然后,您必须将cropImage()转换为实际使用promise逻辑并返回一个promise。

var cropImage = function(data){
  console.log("cropImage")
  return gm("./lib/card.png")
    .crop(data.width, data.height, data.x, data.y)
    .writeAsync("./lib/avatar.png").then(function() {
        fs.unlink("./lib/card.plist")
        fs.unlink("./lib/card.png")
        console.log("Image Created")
    });
    // Note: You are missing error handling for writeAsync
}

这应该允许你这样做:

getXML()
  .then(writeXML)
  .then(getSprite)
  .then(writeSprite)
  .then(parseXML)
  .then(cropImage)
  .then(function() {
      // done successfully here
  }, function(err) {
      // error here
  })

注意:parseXML()中仍有同步文件I / O,可以转换为使用异步I / O.以下是异步文件I / O可以返回在当前方案中有效的承诺:

var parseXML = function() {
  console.log("parseXML")
  return fs.readFileAsync("./lib/card.plist", "utf8").then(function(file) {
      var obj = plist.parse(file);
      var framename = card.slug + "_idle_000.png"
      var frame = obj.frames[framename].frame
      var values = frame.replace(/[{}]/g, "").split(",")
      var data = { x: values[0], y: values[1], width: values[2], height: values[3] }
      return data
  });
}