【问题标题】:Getting Promise { <pending> } while working with Nodejs in IBM cloud function在 IBM 云功能中使用 Nodejs 时获得 Promise { <pending> }
【发布时间】:2019-09-09 16:18:25
【问题描述】:

我阅读了几个与之相关的答案,但只是感到困惑。

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

为此,我使用 Nodejs 作为运行时创建了一个“读取操作”。 我在其中编写了以下代码,它显示了“Promise pending”错误。

这是我的代码:

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}"

【问题讨论】:

  • 尝试使用getItem(BUCKET, FILE).then(results =&gt; console.log(results))。因为getItem() 是一个返回承诺的异步函数。

标签: node.js


【解决方案1】:

简答

这不是错误,这实际上是返回的值 - 一个未决的承诺。 Read this 了解什么是承诺。您会看到这一点,因为在您记录该值时,该值还不存在 - 仍在获取 CSV 数据。

为了立即解决您的问题,您需要更改它...

console.log(getItem(BUCKET, FILE))

...到这个:

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

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

此外,您还需要添加这个...

return data

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

长答案

Promise {pending} 不是错误。这是getItem 函数的返回值:一个未决的承诺。

如果你不知道关于他们的承诺是什么here

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

如果 Promise 起作用,显示操作执行顺序的简短示例:

// 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 返回一个承诺,并且使用 main 的外部代码也必须知道如何处理承诺,等等。幸运的是,IBM 云确实支持异步响应,所以只要确保你也从 main 返回了一个承诺,例如使用return getItem(BUCKET, FILE)

更好的解决方案

如果您使用 Node v8 附带的async/await syntax,代码的读写会变得更好。如果您选择正确的运行时,IBM 云允许使用节点 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
}

这仍然在底层使用 Promise,但新语法允许您以一种更自然、更易于理解的方式编写代码。

【讨论】:

  • 非常感谢。您的描述帮助我全面了解了问题,并获得了所需的输出
  • 不客气!作为新人:习惯使用“接受”按钮来标记解决您问题的答案。这样其他人会立即看到这个答案。
【解决方案2】:

getItem 将返回一个 Promise。您可以在最后标记 .then,并在 Promise 解决时调用回调函数。

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

希望这会有所帮助!

【讨论】:

  • 是的,它确实帮助了我。谢谢
猜你喜欢
  • 2018-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-28
  • 2021-12-01
  • 2021-07-03
  • 1970-01-01
相关资源
最近更新 更多