在IBM Cloud功能中使用Nodejs时获得承诺{<pending>}

时间:2019-09-04 17:37:49

标签: node.js

我读了一些与此有关的答案,但只是感到困惑。

所以,我的问题是: 我必须使用IBM云功能读取存储在IBM云对象存储中的CSV文件的内容。

为此,我使用Nodejs作为运行时创建了一个“读取动作”。 我在其中编写了以下代码,并显示了“未决承诺”错误。

这是我的代码:

const COS = require('ibm-cos-sdk').S3

function main (params) {
  const IAM_API_KEY = process.env.__OW_IAM_NAMESPACE_API_KEY
  const ENDPOINT = 's3.eu-gb.cloud-object-storage.appdomain.cloud'
  const BUCKET = 'my-bucket'
  const FILE = 'Sample.csv'

  const config = {
    endpoint: ENDPOINT,
    apiKeyId: IAM_API_KEY
  }

  const cos = new COS(config)

  const options = {
    Bucket: BUCKET
  }

  function getItem (bucketName, itemName) {
    console.log(`Retrieving item from bucket: ${bucketName}, key:${itemName}`)

    return cos.getObject({
      Bucket: bucketName,
      Key: itemName
    }).promise()
      .then((data) => {
        if (data != null) {
          console.log('File Contents: ' + Buffer.from(data.Body).toString())
          console.log('hellllllo')
        }
      })
      .catch((e) => {
        console.error(`ERROR: ${e.code} - ${e.message}\n`)
      })
  }

  console.log(getItem(BUCKET, FILE))
}

输出:

Retrieving item from bucket: 
my-bucket, key: Sample.csv",

"2019-09-01T19:28:35.905526Z stdout: Promise {pending}"

2 个答案:

答案 0 :(得分:1)

简短答案

这不是错误,实际上是返回的值-未完成的承诺。 Read this了解承诺。之所以会看到这种情况,是因为在记录该值时,该值甚至还没有到达-仍在获取CSV数据。

作为针对您的问题的立即解决方案,您需要对此进行更改...

console.log(getItem(BUCKET, FILE))

...对此:

return getItem(BUCKET, FILE).then((data) => {
  console.log(data)
})

这会将承诺返回给IBM云,以便它可以等待操作完成,并且仅在返回数据后立即执行console.log语句,而不是立即执行。

此外,您将需要添加...

return data

...在您的then调用内(在if (data !== null)块下面)的回调结束时–否则,您现在只能在外面看到undefined

长答案

Promise {pending}不是错误。这是getItem函数的返回值:待处理的诺言。

如果您不知道关于他们的承诺here

简而言之,promise表示异步完成的操作。在您console.log兑现诺言的那一刻,它甚至还没有价值,因为CSV提取操作仍在进行中。

一个简短的示例,用于显示诺言发挥作用时的操作执行顺序:

// Let's assume that the function delay(s) returns a promise that
// resolves only after the given amount of seconds has elapsed

console.log('A')
delay(1).then(function () {
  console.log('B')
  return delay(2)
}).then(function () {
  console.log('C')
})
console.log('D')

// Output will be:
// (immediately)
//   A
//   D <<<<< !!!!!!!
// (1 second later)
//   B
// (2 seconds later)
//   C

为说明正在发生的情况,让我将代码简化为发生的部分,直到看到此日志输出为止:

  function getItem (bucketName, itemName) {
    console.log(`Retrieving item from bucket: ${bucketName}, key:${itemName}`)

    return somePromise
  }

  console.log(getItem(BUCKET, FILE))

当然,somePromise在您的代码中并不作为变量存在,但是我在这里使用它来表示cos.getObject(...).promise()的返回值,这是一个承诺。

因此,在代码的初始执行中,您看到Retrieveing item from bucket,然后看到返回的值,即未完成的承诺。这符合您的描述。

但是,此时您的代码尚未完成。提取操作仅已启动,尚未完成。完成后,您的thencatch处理程序中的代码也将运行!因此,我希望稍后,您还会在输出中看到File Contents:...helllllloERROR:...。 (如果不这样做,那么您的执行环境可能不支持异步任务,或者执行时间限制太短。)

如果以后会看到输出,但是不确定如何在其他代码中使用获取的值:一旦有了任何异步组件,使用该组件的所有代码本身就必须是异步的。这意味着,您不能简单地return中的值main,例如,您还必须从main返回一个promise,并且使用main的外部代码还必须知道如何兑现承诺,等等。幸运的是,IBM云确实支持异步响应,因此只需确保您还从main返回了Promise,例如使用return getItem(BUCKET, FILE)

更好的解决方案

如果使用Node v8随附的async/await syntax,则代码的可读性和可读性会更好。如果选择正确的运行时,IBM Cloud允许使用节点v8。在这种情况下,异步代码将简化为:

const COS = require('ibm-cos-sdk').S3

async function main (params) { // <<< async keyword added
  const IAM_API_KEY = process.env.__OW_IAM_NAMESPACE_API_KEY
  const ENDPOINT = 's3.eu-gb.cloud-object-storage.appdomain.cloud'
  const BUCKET = 'my-bucket'
  const FILE = 'Sample.csv'

  const config = {
    endpoint: ENDPOINT,
    apiKeyId: IAM_API_KEY
  }

  const cos = new COS(config)

  const options = {
    Bucket: BUCKET
  }

  async function getItem (bucketName, itemName) { // <<< async keyword added
    console.log(`Retrieving item from bucket: ${bucketName}, key:${itemName}`)

    try {
        const data = await cos.getObject({ // <<< turned into assignment with await
          Bucket: bucketName,
          Key: itemName
        }).promise() // <<< no .then with callback needed

        if (data != null) {
          console.log('File Contents: ' + Buffer.from(data.Body).toString())
          console.log('hellllllo')
        }

        return data
      } catch (e) { // <<< turned into simple catch
        console.error(`ERROR: ${e.code} - ${e.message}\n`)
      }
  }

  console.log(await getItem(BUCKET, FILE)) // <<< await keyword added
}

这仍然在后台使用了promises,但是新语法允许您以一种看起来更自然,更易于理解的方式编写代码。

答案 1 :(得分:0)

getItem将返回一个承诺。最后,您可以使用回调函数标记.then,当Promise解决后,该回调函数将被调用。

getItem(BUCKET, FILE).then(results => {
    console.log(results);
});

希望这会有所帮助!