我读了一些与此有关的答案,但只是感到困惑。
所以,我的问题是: 我必须使用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}"
答案 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
,然后看到返回的值,即未完成的承诺。这符合您的描述。
但是,此时您的代码尚未完成。提取操作仅已启动,尚未完成。完成后,您的then
或catch
处理程序中的代码也将运行!因此,我希望稍后,您还会在输出中看到File Contents:...
和hellllllo
或ERROR:...
。 (如果不这样做,那么您的执行环境可能不支持异步任务,或者执行时间限制太短。)
如果以后会看到输出,但是不确定如何在其他代码中使用获取的值:一旦有了任何异步组件,使用该组件的所有代码本身就必须是异步的。这意味着,您不能简单地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);
});
希望这会有所帮助!