在 Node.js 中,数组在调试中填充得更多,但在正常模式下不填充

Array populated in debug more but not in in normal mode in Node.js

在下面的代码中,当我 运行 处于调试模式并在此行处设置一个断点时:content.push(data.Body.toString()); 我可以看到数据已插入到 content 数组中。

然而,当我 运行 代码正常时,content 返回空。

我怎样才能让它填充数组以供下游使用?

var params = { Bucket: "thebucket", Prefix: "theprefix/" }
var content = [];
function getS3Data()
{    
var s3 = new aws.S3();
s3.listObjects(params, function (err, data) 
{        
    if (err) throw err; // an error occurred
    else 
    {            
        var i;
        for (i = 0; i < data.Contents.length; i++)              
        {
            var currentValue =  data.Contents[i];
            if(currentValue.Key.endsWith(params.Prefix) == false) 
            {
                var goParams = { Bucket: params.Bucket, Key: currentValue.Key };                   
                s3.getObject(goParams, function(err, data) 
                {                        
                    if (err) throw err; //error                        
                    content.push(data.Body.toString());       
                });
            };
        };            
    }//else
});//listObjects
}//getS3Data

getS3Data();

console.log(content); //prints empty here when run in non-debug.

Node.js' 文档中有一个与您遇到的问题非常相似的示例:

问题的出现是因为变量 content 没有在 getS3Data 完成后立即设置,因为它是一个 asynchronous 函数。 content 稍后设置。但是您对 console.log(content); 的调用将在 getS3Data 完成后立即执行,因此此时 content 尚未设置。

您可以通过添加额外的日志来测试它:

s3.getObject(goParams, function(err, data) 
{                        
    if (err) throw err; //error                        
    content.push(data.Body.toString());
    console.log("Content has been assigned");
});

然后将底部改为:

getS3Data();
console.log("getS3Data has finished", content);

您可能会按以下顺序收到消息:

getS3Data has finished
Content has been assigned

行:
console.log(content)
正在行之前执行:
content.push(data.Body.toString());

您作为第二个参数传递给 s3.listObjects 的函数将异步执行。如果你想注销 content 你需要在回调函数中进行,意思是:

s3.listObjects(params, function (err, data) {        
    if (err) throw err;
    else {            
        // ...
        console.log(content)
    }
});

更好的方法是使用 Promise 实现 getS3Data,这样您就可以 运行 在确定对象列表完成后编写代码。

function getS3Data() {
    return new Promise((resolve, reject) => {
        if (err) {
            reject(err)
        } else {
            const promises = []
            for (const i = 0; i < data.Contents.length; i++) {
                const currentValue = data.Contents[i];
                if (currentValue.Key.endsWith(params.Prefix) == false) {
                    const goParams = { Bucket: params.Bucket, Key: currentValue.Key };
                    promises.push(new Promise((res, rej) => {
                        s3.getObject(goParams, function (err, data) {
                            if (err) {
                                rej(err); //error
                            } else {
                                res(data.Body.toString());
                            }                        
                        });
                    }));
                }
            }
            Promise.all(promises).then(resolve);
        }
    });
}

getS3Data()
    .then(result => { // this will actually be `content` from your code example
        console.log(result);
    }).catch(error => {
        console.error(error);
    })