如何在循环中正确实现异步或等待操作 - nodejs

时间:2018-04-10 14:24:52

标签: node.js

我是nodejs的新手所以请原谅我是否想念显而易见的事情。 我目前正在努力处理代码的异步操作。它是这样的。我运行快速框架来调用调用外部REST服务器的特定URL来获取有关对象的一些信息。我没有基本操作的问题,我处理REST响应,解析JSON并将信息传递给EJS视图引擎以呈现HTML页面。 但是,我遇到了一个特定进程的问题,在我得到我的REST响应(卷列表)之后,然后我想运行另一个REST调用以获取有关每个卷的更多详细信息(在循环中)。检索完成后,我想调用EJS来呈现包含卷列表及其详细信息的页面。 这是我的代码:

function listVolumes(req, res) {
        var element = 'volume';
        var element_list= [];
        var output_json = [];
        var options = { method: 'GET',
                url: MY_ENV.MY_URL + '/v2/volumes',
          headers: 
           { 
             'Cache-Control': 'no-cache',
             'X-Auth-Token': MY_ENV.MY_TOKEN,
             'Content-Type': 'application/json',
             'Accept': 'application/json' }
        }
            request(options) // using request-promise
                .then(function (body) {
                output_json = JSON.parse(body); // parsing array of JSON objects from REST server
                if (Object.keys(output_json).length > 0){
                    for (var i in output_json.list) { // iterating over list of JSON objects
                        var volume_id = output_json.list[i];
                        console.log(i, ': ' , JSON.stringify(volume_id, null, 3));
                        getVolumeDetails(volume_id, function callback(volume){ // getting volume details
                            element_list.push({ id: volume_id, name: volume.name, size: volume.size, state: volume.state });
                        });
                    }
                    res.render('listVolumes', {element, element_list, output_json }); // calling ejs view-engine to render html page
                } else console.log('No volumes found.');
            })
                .catch (function (error) {
                    console.log('Got error while listing ' + element , error);
                });
}
function getVolumeDetails(volume_id, callback){
    var options = { method: 'GET',
            url: MY_ENV.MY_URL + '/v2/volumes/' + volume_id,
      headers: 
       { 
         'Cache-Control': 'no-cache',
         'X-Auth-Token': MY_ENV.MY_TOKEN,
         'Content-Type': 'application/json',
         'Accept': 'application/json' } };
    request(options)
        .then(function (body) {
            volume = JSON.parse(body);
            console.log('got volume: ' , volume.name , volume.size, volume.state);
            callback(volume);
        })
        .catch (function (error) {
        console.log('Got error while reading volume: ' + volume_id , error.message);
        }); 

}
app.get('/list/volumes', listVolumes);

很明显,当我调用EJS时,它会呈现HTML页面,之后我会获得getVolumeDetails()的控制台消息,因为javascript的异步特性。 我读过很多关于使用request-promise,async.each,async wait,callbacks的文章,并且仍然很难理解如何使它工作。我不介意等待几秒钟让循环完成获取所有卷的详细信息,用我想要在HTML页面上显示的项目数组填充我的element_list。 你可以帮我指导一下构造使用的方法和方法吗?

感谢。

1 个答案:

答案 0 :(得分:0)

这是我的修改:

function listVolumes(req, res) {
    var element = 'volume';
    var element_list= [];
    var output_json = [];
    var options = { method: 'GET',
            url: MY_ENV.MY_URL + '/v2/volumes',
      headers: 
       { 
         'Cache-Control': 'no-cache',
         'X-Auth-Token': MY_ENV.MY_TOKEN,
         'Content-Type': 'application/json',
         'Accept': 'application/json' }
    }
    request(options)
        .then(function (body) {
        output_json = JSON.parse(body);
        console.log('Raw body of listVolumes(): \n' , body);
        if (Object.keys(output_json).length > 0){
            async.each(output_json.list, function (volume_id, callback){
                options.url = MY_ENV.MY_URL + '/v2/volumes/' + volume_id;
                request(options)
                    .then(function (body) {
                        var volume = JSON.parse(body);
                        console.log('got callback: ' , volume.id, volume.name , volume.size, volume.state);
                        element_list.push({ id: volume.id, name: volume.name, size: volume.size, state: volume.state });
                        callback(null);
                    })
                    .catch (function (error) {
                    console.log('Got error while reading volume: ' + volume_id , error.message);
                    });
            }, 
            function (err){
                if (err) {
                    console.log('Error occured: ', err);
                } else {
                    console.log('All done...Element list length: ', element_list.length); // this never runs... why???
                }
                res.render('listVolumes', {element, element_list, output_json });
            });
        } else console.log('No volumes found.');
    })
    .catch (function (error) {
        console.log('Got error while listing ' + element , error);
    });
}

因此它永远不会运行函数(错误)中的代码,我将注释// this never runs... why???

放在其中